[轉] Sails+AngularJs+Mocha整合

By combining the power of Sailsjs + Angular.js + Mocha, we will get the most full funtional and powerful web framework.

  • Sails.js will work itself as a backend on connecting DB and being a socket update.
  • Angular.js will be the promising front-end which you can stab MV** to your own UI
  • Mocha will help you testing your code

    Requirements

    • Sails.js – v0.10.0-rc7

    How?

    1. Create a new Sails app sails new myapp
    2. Adding angular-seed to sails
      2.1 Wipe out the contents under myapp/assets
      2.2 clone (angular-seed)[https://github.com/angular/angular-seed] and copy the contents under app to replace myapp/assets
      2.3 Copy angular-seed/bower.json to myapp/bower.json
      2.4 Add myapp/.bowerrc telling it to set bower folder as root directory

      { "directory": "./bower_components"}

      2.5 Setting sails to copy angular js to .tmp/public/js/dependencies and .tmp/public/styles which will appear on index.html by changing tasks/config/copy.js as follow:

      module.exports = function(grunt) {
        grunt.config.set('copy', {
            dev: {
                files: [{
                    expand: true,
                    cwd: './assets',
                    src: ['**/*.!(coffee|less)'],
                    dest: '.tmp/public'
                },{
                    expand: true,
                    cwd: './bower_components',
                    src: [
                        'angular/angular.js', 'angular-route/angular-route.js','angular-mocks/angular-mocks.js', 'angular-loader/angular-loader.js',
                    ],
                    flatten: true,
                    dest: '.tmp/public/js/dependencies'
                }]
            },
            build: {
                files: [{
                    expand: true,
                    cwd: '.tmp/public',
                    src: ['**/*'],
                    dest: 'www'
                }]
            }
            });
            grunt.loadNpmTasks('grunt-contrib-copy');
        };

      Try to run sails lift and go to localhost:1337. If you see sourcecode, you will see all angular js have been included in the page.
      2.6 Adding automatic bower install for npm in package.json

      • npm install bower --save
      • Added "postinstall": "./node_modules/.bin/bower install" under "scripts" topics as follow:
      "scripts": {
          "start": "node app.js",
          "debug": "node debug app.js",
          "postinstall": "./node_modules/.bin/bower install"
      },

      2.7 Run ‘npm install’ then you should see ./bower_components folder created

    3. Added bootstrap
      3.1 run bower install --save bootstrap on root directory
      3.2 set sails to copy bootstrap css/js to .tmp/public/js/dependencies and .tmp/public/styles which will appear on index.html. So, your tasks/config/copy.js becomes:

      module.exports = function(grunt) {
      
           grunt.config.set('copy', {
               dev: {
                   files: [{
                       expand: true,
                       cwd: './assets',
                       src: ['**/*.!(coffee|less)'],
                       dest: '.tmp/public'
                   },{ 
                       expand: true,
                       cwd: './bower_components',
                       src: [
                      // add angular js
                       'angular/angular.js', 'angular-route/angular-route.js','angular-mocks/angular-mocks.js', 'angular-loader/angular-loader.js',
                       // add bootstrap & jquery js
                       'bootstrap/dist/js/bootstrap.js','jquery/dist/jquery.js'
                       ],
                       flatten: true,
                       dest: '.tmp/public/js/dependencies'
                   },{ // add bootstrap css
                       expand: true,
                       cwd: './bower_components',
                       src: [
                       'bootstrap/dist/css/bootstrap.css',
                       'bootstrap/dist/css/bootstrap-theme.css'
                       ],
                       flatten: true,
                       dest: '.tmp/public/styles'
                   }]
               },
               build: {
                   files: [{
                       expand: true,
                       cwd: '.tmp/public',
                       src: ['**/*'],
                       dest: 'www'
                   }]
               }
           });
      
           grunt.loadNpmTasks('grunt-contrib-copy');
       };

      So, if you run sails lift again, you should see the difference in index.html.

    4. Return some sails file back to assets
      4.1 make folder assets/js/dependencies
      4.2 put back sails.io.js to assets/js/dependcies
      4.3 put back importer.less to assets/styles
    5. Then, let’s reorder all files in index.html by changing tasks/pipeline.js for js/css variables as follows:
      var cssFilesToInject = [  
        'styles/bootstrap.css',
        'styles/bootstrap-theme.css',
        'styles/**/*.css'
      ];
      
      var jsFilesToInject = [  
        'js/dependencies/sails.io.js',
        'js/dependencies/angular.js',
        'js/dependencies/angular-route.js',
        'js/dependencies/jquery.js',
        'js/dependencies/**/*.js',
        'js/app.js',
        'js/services.js',
        'js/controllers.js',
        'js/filters.js',
        'js/directives.js',
        'js/**/*.js'
      ];

      If you run sails lift and see index.html sourcecode, you should see it reorder as we defined.

    6. Start Angular base template by
      6.1 Adding ng-app="myApp" to html tag -> <html ng-app="myApp">
      6.2 Adding following code before <%- body %>

      <ul class="menu">  
          <li><a href="#/view1">view1</a></li>
          <li><a href="#/view2">view2</a></li>
      </ul>

      You should see Angular already integrated with Sails.

    7. Lastly, let’s delete files we don’t use anymore:
      assets/index.html  
      assets/index-async.html  

      Because sails will create index.html for us from views/layout.ejs

      Let’s Rock! You can now start making API backend using sails and make a change on UI via Angularjs under assets.

文章來源: https://www.youtube.com/playlist?list=PLf8i4fc0zJByWVBmMk8uJ0UEhTIGMnmPQ

[Angular] Directive template with ng-repeat

不要在將 ng-repeat 放在 directive template 的第一行,否則 link function 會抓不到真正的 element,會變成 “comment" element。今天下午同事發現這個問題被搞了很久

Don’t use ng-repeat in the first line to directive template. If do this, the link function’s element will show “comment" element but not the actual one.

AngularJS – 一些不錯的教學

http://hamisme.blogspot.tw/search/label/AngularJS

http://www.thinkster.io/pick/GtaQ0oMGIl/a-better-way-to-learn-angularjs

http://todomvc.com/

AngularJS – angular.Module常用API

以下介紹angular.Module幾個常用的API,更多方法請至官網查看:http://docs.angularjs.org/api/angular.module

A. angular.module: 給前端ng-app用的模組產生器函數。用法:angular.module(name[, requires], configFn); 回傳值:angular.Module

PS: [requires]通常包括:’name.filters’, ‘name.services’, ‘name.directives’

B. angular.Module API介紹:

1.config(configFn): 設定時期的函數區塊configFn(injectables)。injectables是一些provider, 例如: $routeProvider

2.run(initializationFn): 所有module都載入後初始的執行區塊initializationFn(injectables)。 injectables是一些變數, 例如: $rootScope

3.value(name, object): 設定service的key-value。例如: value(‘version’, ‘0.1’)

4.factory(name, providerFunction): 跟service方法類似,但可以回傳更複雜的Object。例如: factory(‘getNum’, function(){return 123;})

5.filter(name, filterFactory): 專門做過濾的factory類型,用|接前端的param變數。例如:app.filter(‘greet’, function() {

return function(param) {
return ‘Hello, ‘ + param+ ‘!’;
};

});

6.directive(name, directiveFactory): 用法見之前文章

Configuration Blocks: (一般config的縮寫)

  1. angular.module(‘myModule’, []).
  2. value(‘a’, 123).
  3. factory(‘a’, function() { return 123; }).
  4. directive(‘directiveName’, …).
  5. filter(‘filterName’, …);
  6. // is same as
  7. angular.module(‘myModule’, []).
  8. config(function($provide, $compileProvider, $filterProvider) {
  9. $provide.value(‘a’, 123);
  10. $provide.factory(‘a’, function() { return 123; });
  11. $compileProvider.directive(‘directiveName’, …);
  12. $filterProvider.register(‘filterName’, …);
  13. });

factory, service, provider(value) 之間的差異

http://stackoverflow.com/questions/16565105/angularjs-what-is-difference-of-creating-service-method-between-module-service-a

AngularJS – controller簡介

controller就像是MVVM中的「view model」,可以在一個app下定義多個controller, 每個controller包含不同的callback function, 用法:

var app = angular.module(‘myApp’, []);

app.controller(‘ctrlName’, function($scope){

$scope.Func1 = function(){

//detail of the callback function

}

});

AngularJS – directives簡介

directives是AngularJS重要的屬性,可以讓特定element以自訂屬性達到模組化功能。使用方法:

var app = angular.module(‘myApp’, []);

app.directive(‘directiveName’, function(){

restrict: ‘指定此directive的使用方式, 有A(屬性)/E(元素)/C(類別)/M(註解), 以A和E較常用’, ex: A: <div my-directive="exp"></div>, E: <my-directive>,

controller: function($scope){

this.Func1 = function(){ 自訂此controller的callback函數; }

},

template: ‘預先寫好的html片段’,

replace: ‘如果設為true則template會取代原來的元素,否則append到原來的元素’,

compile: funcion(element, attrs, transclude){ //先於link,編譯template到DOM元素

//return link function物件;

},

link: funcion(scope, element, attrs, ctrl){ //將local scope變數與DOM元素建立關聯

element.bind(‘eventName’, function(){

套用的element綁定事件callback, 後面的attr和ctrl兩參數可作用在其他的element上,

ex: scope.$apply.(attr.enter); //當element觸發’eventName’事件時, 執行此scope的所有具有enter屬性的回呼函數

});

},

priority: ‘當一個DOM元素包含多重directive,可設定此directive優先權。值愈大愈高,預設值是0’,

terminal: ‘如果設為true,在有設priority的多重directive下,執行到此directive時就會中止’,

scope: ‘true 或 {}’, //如果設為:

/*

true – 此directive會產生一個新的scope。注意: 多重directive的元素,只會有一個新scope。此設定不適用有template的情況,template有自己的’isolate’ scope。

{} – 獨立於directive的’isolate’ scope將會套用在此directive的template。{}裡的property可衍生parent的scope變數到自己的scope:
。@ 或 @attr – 綁定此DOM的屬性,得到的永遠是string。例如template: <widget my-attr="hello {{name}}">,此widget有scope: { localName:’@myAttr’ },則這裡localName的值會反映到parent scope的{{name}}
。= 或 =attr – local scope與parent scope的屬性雙向綁定,改變會互相反映。如果parent scope的屬性不存在會拋出NON_ASSIGNABLE_MODEL_EXPRESSION錯誤,避免這情況可以設為=? 或 =?attr。
例如:template: <widget my-attr="parentModel">,此widget有scope: { localModel:’=myAttr’ },則這裡localModel的值和parent scope的parentModel會互相反映。
。& 或 &attr – 綁定計算的expression。例如template: <widget my-attr="count=count+value">,此widget有scope: { localFn:’&myAttr’ },則這裡localFn會指向count=count+value表達式。
綜合範例:
<div ng-show="visible">
<h3>{{title}}</h3>
<div class="body" ng-transclude></div>
<div class="footer">
<button ng-click="onOk()">Save changes</button>
<button ng-click="onCancel()">Close</button>
</div>
</div>
可用以下的scope設定綁定:
scope: {
title: ‘@’, // the title uses the data-binding from the parent scope
onOk: ‘&’, // create a delegate onOk function
onCancel: ‘&’, // create a delegate onCancel function
visible: ‘=’ // set up visible to accept data-binding
}

*/

});

useful live demo:

http://jsfiddle.net/colvint/uAwJG/

https://github.com/angular/angular.js/wiki/JSFiddle-Examples