Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

AngularJS, More Than Directives !

258 views

Published on

The presentation walks you through few topics on AngularJS which if known to the developer, makes life a little easy.

Published in: Engineering
  • Be the first to comment

  • Be the first to like this

AngularJS, More Than Directives !

  1. 1. AngularJS, More Than Directives! - Gaurav Behere - http://www.gauravbehere.in
  2. 2. Topics Covered A. Apply/Digest Phase Cycle. B. Handling Memory. C. Transclusion. D. Promises. E. Watch.
  3. 3. Apply/Digest Cycle $digest: $digest processes all the watch-Expressions for the current scope and its children What happens when a watch-Expression is processed? The value of the current watch-Expression is compared with the value of the previous watch-Expression, and if they do not match then it is “dirty” and a listener is fired. This is what we call as “Dirty Checking”. Angular doesn’t directly call $digest(). Instead, it calls $scope.$apply(), which in turn calls $rootScope.$digest(). As a result of this, a digest cycle starts at the $rootScope, and subsequently visits all the child scopes calling the watchers along the way.
  4. 4. Now, let’s assume you attach an ng-click directive to a button and pass a function name to it. When the button is clicked, AngularJS wraps the function call within $scope.$apply(). So, your function executes as usual, change models (if any), and a $digest cycle starts to ensure your changes are reflected in the view. When & why should I call apply() manually ? When an external event (such as a user action, timer or XHR) is received, the associated expression must be applied to the scope through the $apply() method so that all listeners are updated correctly. It will account for only those model changes which are done inside AngularJS’ context (i.e. the code that changes models is wrapped inside $apply()). Angular’s built-in directives already do this so that any model changes you make are reflected in the view. However, if you change any model outside of the Angular context, then you need to inform Angular of the changes by calling $apply() manually. It’s like telling Angular that you are changing some models and it should fire the watchers so that your changes propagate properly. For example, if you use JavaScript’s setTimeout() function to update a scope model, Angular has no way of knowing what you might change. In this case it’s your responsibility to call $apply() manually, which triggers a $digest cycle. Similarly, if you have a directive that sets up a DOM event listener and changes some models inside the handler function, you need to call $apply() to ensure the changes take effect
  5. 5. Example If you use JavaScript’s setTimeout() function to update a scope model, Angular has no way of knowing what you might change. In this case it’s your responsibility to call $apply() manually, which triggers a $digest cycle. HTML <body ng-app="myApp"> <div ng-controller="MessageController"> Delayed Message: {{message}} </div> </body> JS /*Without Apply*/ angular.module('myApp',[]).controller('MessageController', function($scope) { $scope.getMessage = function() { setTimeout(function() { $scope.message = 'Fetched after 3 seconds'; }, 2000); $scope.getMessage(); } JS /*With Apply*/ angular.module('myApp',[]).controller('MessageController', function($scope) { $scope.getMessage = function() { setTimeout(function() { $scope.$apply(function() { $scope.message = 'Fetched after 3 seconds'; }); }, 2000); } $scope.getMessage(); });
  6. 6. Handling Memory $destroy() Removes the current scope (and all of its children) from the parent scope. Removal implies that calls to $digest() will no longer propagate to the current scope and its children. Removal also implies that the current scope is eligible for garbage collection. The $destroy() is usually used by directives such as ngRepeat for managing the unrolling of the loop. Just before a scope is destroyed a $destroy event is broadcasted on this scope. Application code can register a $destroy event handler that will give it chance to perform any necessary clean-up. Scope.$destroy(); Calling $destroy() on a scope causes an event “$destroy” to flow downstream.
  7. 7. Why & when should I manually handle memory ? If you are using timers to update scope. In cases where you have event listeners. As an example, the following controller continuously updates a model value in one second intervals, and these updates will continue forever, even after the controller’s view is gone and the scope is removed from its parent. module.controller("TestController", function($scope, $timeout) { var onTimeout = function() { $scope.value += 1; $timeout(onTimeout, 1000); }; $timeout(onTimeout, 1000); $scope.value = 0; }); Listening for the $destroy event is an opportunity to halt the timer module.controller("TestController", function($scope, $timeout) { var onTimeout = function() { $scope.value += 1; timer = $timeout(onTimeout, 1000); }; var timer = $timeout(onTimeout, 1000); $scope.value = 0; $scope.$on("$destroy", function() { if (timer) { $timeout.cancel(timer); } }); });
  8. 8. Promises The AngularJS $q service is said to be inspired by Chris Kowal's Q library (github.com/kriskowal/q). The library's goal is to allow users to monitor asynchronous progress by providing a "promise" as a return from a call. In AngularJS, the semantics of using a promise are: var promise = callThatRunsInBackground(); promise.then( function(answer) { // do something }, function(error) { // report something }, function(progress) { // report progress });
  9. 9. A number of Angular services return promises: $http, $interval, $timeout, for example. All promise returns are single objects; you're expected to research the service itself to find out what it returns. For example, for $http.get, the promise returns an object with four keys:data, status, headers, and config. Those are the same as the four parameters fed to the success callback if you use those semantics: // this $http.get('/api/v1/movies/avengers') .success(function(data, status, headers, config) { $scope.movieContent = data; }); // is the same as var promise = $http.get('/api/v1/movies/avengers'); promise.then( function(payload) { $scope.movieContent = payload.data; });
  10. 10. Deferring Promises, Defining Custom Promises: function asyncGreet(name) { var deferred = $q.defer(); setTimeout(function() { deferred.notify('About to greet ' + name + '.'); if (okToGreet(name)) { deferred.resolve('Hello, ' + name + '!'); } else { deferred.reject('Greeting ' + name + ' is not allowed.'); } }, 1000); return deferred.promise; } var promise = asyncGreet('Robin Hood'); promise.then(function(greeting) { alert('Success: ' + greeting); }, function(reason) { alert('Failed: ' + reason); }, function(update) { alert('Got notification: ' + update); });
  11. 11. Chaining Promises defer.promise .then(function () { alert("I promised I would show up"); }) .then(function () { alert("me too"); }) .then(function () { alert("and I"); }); defer.resolve(); It is also possible to resolve with parameters. The chained promises will cascade their return values to the subsequent promise: defer.promise .then(function (weapon) { alert("You can have my " + weapon); return "bow"; }) .then(function (weapon) { alert("And my " + weapon); return "axe"; }) .then(function () { alert("And my " + weapon); }); defer.resolve("sword");
  12. 12. Transclusion Transclusion provides a way for a consumer of a directive to define a template that is imported into the directive and displayed. For example you might have a directive that outputs a table while allowing the consumer of the directive to control how the table rows are rendered. Or, you might have a directive that outputs an error message while allowing the consumer of the directive to supply HTML content that handles rendering the error using different colors. By supporting this type of functionality the consumer of the directive has more control over how specific parts of the HTML generated by the directive are rendered. Two key features are provided by AngularJS to support transclusion. The first is a property that is used in directives named transclude. When a directive supports transclusion this property is set to true. The second is a directive named ng-transclude that is used to define where external content will be placed in a directive’s template
  13. 13. Markup <div ng-app="phoneApp"> <div ng-controller="AppCtrl"> <panel> <div class="button">Click me!</div> </panel> </div> </div> var app = angular.module('phoneApp', []); app.controller("AppCtrl", function ($scope) { }); app.directive("panel", function () { return { restrict: "E", template: '<div class="panel">This is a panel component</div>' } }); return { restruct: "E", transclude: true, template: '<div class="panel" ng-transclude>This is a panel component </div>' }
  14. 14. Watch The $scope.watch() function creates a watch of some variable. When you register a watch you pass two functions as parameters to the $watch() function: A value function A listener function Here is an example: $scope.$watch(function() {}, function() {} ); The first function is the value function and the second function is the listener function. The value function should return the value which is being watched. AngularJS can then check the value returned against the value the watch function returned the last time. That way AngularJS can determine if the value has changed. Here is an example: $scope.$watch(function(scope) { return scope.data.myVar }, function() {} ); This example value function returns the $scope variable scope.data.myVar. If the value of this variable changes, a different value will be returned, and AngularJS will call the listener function.
  15. 15. The watchExpression is called on every call to $digest() and should return the value that will be watched. (Since $digest() reruns when it detects changes the watchExpression can execute multiple times per $digest() and should be idempotent.) The listener is called only when the value from the current watchExpression and the previous call to watchExpression are not equal (with the exception of the initial run, see below). Inequality is determined according to reference inequality, strict comparison via the !== Javascript operator, unless objectEquality == true (see next point) When objectEquality == true, inequality of the watchExpression is determined according to the angular.equals function. To save the value of the object for later comparison, the angular.copy function is used. This therefore means that watching complex objects will have adverse memory and performance implications. The watch listener may change the model, which may trigger other listeners to fire. This is achieved by rerunning the watchers until no changes are detected. The rerun iteration limit is 10 to prevent an infinite loop deadlock.
  16. 16. Further Read/References https://docs.angularjs.org/api/ng/type/$rootScope.Scope https://thinkster.io/egghead/promises/ http://chariotsolutions.com/blog/post/angularjs-corner-using-promises-q-handle-asynchronous-calls/ http://andyshora.com/promises-angularjs-explained-as-cartoon.html

×