Things you may not know about AngularJS






Michael Wang // @loveky on GITHUB

Agenda


  • Angular Helper Method
  • About Dependency Injection
  • About Controllers
  • Built-in Services
  • scope.$digest & scope.$apply
  • $destroy event
  • config block & run block
  • About Test
  • Q&A

Angular Helper Method


angular.copy(src, [dst])





angular.extend(dst, src)

Angular Helper Method(cont.)


angular.equals(obj1, obj2)

NaN === NaN
false
angular.equals(NaN, NaN)
true 

/abc/ === /abc/
false
angular.equals(/abc/, /abc/)
true 

obj1 = {a:1, b: function() {alert(1)}, $c: 111}
obj2 = {a:1, b: function() {alert(2)}, $c: 222}
obj1 === obj2
false
angular.equals(obj1, obj2)
true 

Angular Helper Method(cont.)



Use it this way:  

function foo(callback) {
    var result = calculateResult();
    (callback || angular.noop)(result);
}

How it works? 
function noop() {} 

         

About Dependency Injection


Don't do this:

someModule.controller('MyController', function($scope, dep1, dep2) {
  ...
  $scope.aMethod = function() {
    ...
  }
  ...
});


Instead, do this:

someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
  ...
  $scope.aMethod = function() {
    ...
  }
  ...
}]);

About Dependency Injection(cont.)


But why this works?


someModule.controller('MyController', function($scope, dep1, dep2) {
  ...
  $scope.aMethod = function() {
    ...
  }
  ...
});

About Controllers

When NOT to use controller?

  • Manipulate DOM
  • Format input
  • Filter output
  • Share code or state across controllers

Built-in Services


$timeout
$window
$document
$location
$http

VS

window.timeout
window
window.document
window.location
XMLHttpRequest 

Built-in Services (cont.)


Benefits:

  • No global variable
  • More friendly API
  • Fit with AngularJS seamlessly

scope.$digest & scope.$apply


$digest()


Processes all of the watchers of the current scope and its children.


Usually, you don't call $digest() directly, you should use $apply instead.


Except that you may need to call $digest() to simulate the scope life cycle in unit test.

scope.$digest & scope.$apply (cont)


$apply()


$apply() is used to execute an expression in angular from outside of the angular framework.


For example:

  • DOM events
  • setTimeout
  • XHR
  • 3rd party library

scope.$digest & scope.$apply (cont)


Pseudo-Code life cycle

function $apply(expr) {
try {
return $eval(expr);
} catch (e) {
$exceptionHandler(e);
} finally {
$root.$digest();
}
}

scope.$digest & scope.$apply (cont)


$scope.variable = "some value";
executeSomeAction();
$scope.$apply(); 


$scope.$apply(function() {
  $scope.variable = "some value"; 
  executeSomeAction();
});

$destroy event


Angular will broadcast a $destroy event just before tearing down a scope and removing the scope from its parent.


demoApp.controller("HelloController", function($scope, $timeout) {
  var ts = new Date();
  var onTimeout = function() {  
    console.log("logger start at: " + ts);
    timer = $timeout(onTimeout, 1000);
  };
  var timer = $timeout(onTimeout, 1000);
}); 


Don't forget to clean up your $scope!

$destroy event(cont.)


demoApp.controller("HelloController", function($scope, $timeout) {
  var ts = new Date();
  var onTimeout = function() {  
    console.log("logger start at: " + ts);
    timer = $timeout(onTimeout, 1000);
  };
  var timer = $timeout(onTimeout, 1000);
      
  $scope.$on("$destroy", function() {
      if (timer) {
          $timeout.cancel(timer);
      }
  });
}); 

config block & run block


config block

Only providers and constants can be injected into configuration blocks.


run block

Only instances and constants can be injected into run blocks.


Why?

config block & run block(cont.)


function $LogProvider(){
  var debug = true,
      self = this;

  this.debugEnabled = function(flag) {
    if (isDefined(flag)) {
      debug = flag;
    return this;
    } else {
      return debug;
    }
  };   this.$get = ['$window', function($window){
    return {

View code on GitHub

config block & run block(cont.)



angular.module('app', [])
.config(['$logProvider', function($logProvider){
    $logProvider.debugEnabled(false);
}])

About Test


Unit Test

Karma + Jasmine(RSpec like)



End to end test

Protractor(based on WebdriverJS) + Jasmine

Q&A





Thank you!

Made with Slides.com