Tuesday, December 01, 2015

AngularJs Code reading

1. application life-cycle

  • configuration: configures and instantiates all providers
  • run: interaction with providers is disallowed and the process of creating services starts
在optool scala中:
  • configuration阶段(app.js):配置ngRouteProvider, httpProvider, ngDialogProvider
  • run阶段:统一ping,其他行为

2. provider

  • AngularJS的injector会使用recipes创建两类对象
    • services: 接口由开发人员自己定义
    • special purpose objects:包括directive, controller, filter和animation
  • AngularJS的有五种recipes定义如何创建对象:
    • Value
    • Factory
    • Service
    • Provider
    • Constant
注意不要把Provider和Factory混淆。
在Configuration阶段(即module.config函数中),可以引用constant和provider。
  • Factory和Service最常用(optool scala使用factory来定义rest api)。
    • factory可以传入函数或者javascript的primitives
    • service只能之传入一个构造函数指针
  • provider需要返回的对象有一个$get函数, Provider是底层实现,其他的都是syntactic sugar。
// value
myApp.value('clientId', 'a12345654321x');

// factory
myApp.factory('unicornLauncher', ["apiToken", function(apiToken) {
  return new UnicornLauncher(apiToken);
}]);

// service
myApp.service('unicornLauncher', ["apiToken", UnicornLauncher]);

// provider
myApp.provider('unicornLauncher', function UnicornLauncherProvider() {
  var useTinfoilShielding = false;

  this.useTinfoilShielding = function(value) {
    useTinfoilShielding = !!value;
  };

  this.$get = ["apiToken", function unicornLauncherFactory(apiToken) {

    // let's assume that the UnicornLauncher constructor was also changed to
    // accept and use the useTinfoilShielding argument
    return new UnicornLauncher(apiToken, useTinfoilShielding);
  }];
});

// constant
myApp.constant('planetName', 'Greasy Giant');
  • All special purpose objects except for the Controller are defined via Factory recipes.
Features / Recipe type
Factory
Service
Value
Constant
Provider
can have dependencies
yes
yes
no
no
yes
uses type friendly injection
no
yes
yes*
yes*
no
object available in config phase
no
no
no
yes
yes**
can create functions
yes
yes
yes
yes
yes
can create primitives
yes
no
yes
yes
yes
* at the cost of eager initialization by using ``new`` operator directly

** the service object is not available during the config phase, but the provider instance is

3. Scope and Digest

  • Scope object
  • Scope.$watch: 变更注册。注册一个返回的函数和一个回调函数,但变化时,调用回调函数
  • Scope.$digest: 变更通知。遍历$watch注册的函数,根据值的变化,调用相应的回调函数
  • Scope.$apply: 用于外部库接入AngularJS。执行一个函数,该函数用来修改Scope,然后调用$digest触发变更通知
  • Scope.$eval: 执行一个函数,并传递Scope作为其第一个参数
  • Scope.$evalAsync:注册一个将来执行的函数,类似于Javascript里的setTimeout
  • Scope.$applyAysnc: 延迟执行apply

3.1. scope分类

  • angularJS里scope的继承,依赖javascript的prototype chain
  • 这些东西会创建新的scope: ng-repeat, ng-include, ng-switch, ng-view, ng-controller, directive with scope: true, directive with transclude: true.
  • ng-repeat创建scope的方式比较特别,在child scope里增加一个会以repeat的变量名为名字的属性
  • directive有三种:
    • scope: false,直接使用现有的scope,需要小心
    • scope: true,创建自己的scope,并有继承关系
    • scope: {…​},isolated scope 创建自己的scope,没有继承parent scope,但是又$parent属性。这种scope又有三种绑定方式
      • one way: @ 需要传入字符串?或者{{var}}
      • two way: = 传入父scope的属性
      • bind to parent scope expressions: &
<my-directive interpolated="{{parentProp1}}" twowayBinding="parentProp2"> and scope: { interpolatedProp: '@interpolated', twowayBindingProp: '=twowayBinding' }
Assume the directive does this in its linking function: scope.someIsolateProp = "I’m isolated"
isolate scope
  • directive的transclude: true会创建一个新的scope(如下),其中的$$nextSibling可以被ng-transclude使用
transcluded scope

3.2. isolated scope中的 &

Developer Guide中的例子
script.js
angular.module('docsIsoFnBindExample', [])
.controller('Controller', ['$scope', '$timeout', function($scope, $timeout) {
  $scope.name = 'Tobias';
  $scope.message = '';
  $scope.hideDialog = function (message) {
    $scope.message = message;
    $scope.dialogIsHidden = true;
    $timeout(function () {
      $scope.message = '';
      $scope.dialogIsHidden = false;
    }, 2000);
  };
}])
.directive('myDialog', function() {
  return {
    restrict: 'E',          // (1.1)
    transclude: true,
    scope: {
      'close': '&onClose' // (1.2)
    },
    templateUrl: 'my-dialog-close.html'
  };
});
index.html
  {{message}}
  <my-dialog ng-hide="dialogIsHidden" on-close="hideDialog(message)"> // (2)
    Check out the contents, {{name}}!
  </my-dialog>
my-dialog-close.html
<div class="alert">
  <a href class="close" ng-click="close({message: 'closing for now'})">&times;</a> // (3)
  <div ng-transclude></div>
</div>
解读如下:
  • (1.1) (1.2) scope的close属性绑定到onClose element
  • (2) 这里angluarJS会使用 $parse,解析出一个function,在调用该function时,需要传递context和locals对象。这个表达式中涉及identifier需要在context或locals对象中定义(以字段的形式)
  • (3) 当click时,调用(2)中的function,context为父类的scope, locals为 {message: 'closing for now'}
  • 可以看出(2)和(3)中的message需要匹配,否则无法传递参数

0 评论: