banner



How To Call Function In Angularjs Service

Single page apps need the front-terminate developers to go better software engineers. CSS and HTML are not the biggest business anymore, in fact, there is no longer just a single concern. The front end-end developer needs to handle XHRs, awarding logic (models, views, controllers), performance, animations, styles, structure, SEO, and integration with external services. The result which emerges from all those combined is the User Experience (UX) which should always be prioritized.

AngularJS is a very powerful framework. It is the third about starred repository on GitHub. It is non hard to start using, but the goals that it is intended to attain need comprehension. No longer can AngularJS developers ignore memory consumption, because it will not reset on navigation anymore. This is the vanguard of web development. Let'due south encompass it!

Common AngularJS mistakes

Common Mistake #i: Accessing The Telescopic Through The DOM

At that place are a few optimization tweaks recommended for production. One of them is disabling debug info.

DebugInfoEnabled is a setting which defaults to truthful, and allows for scope access through DOM nodes. If you want to try that through the JavaScript console, select a DOM element and access its telescopic with:

          angular.element(document.torso).scope()                  

It tin can be useful even when not using jQuery with its CSS, but should not be used outside of the console. The reason beingness that when $compileProvider.debugInfoEnabled is gear up to false, calling .scope() on a DOM node volition return undefined.

That is 1 of the few recommended options for production.

Please annotation that you can still access the telescopic through the console, even when on product. Phone call angular.reloadWithDebugInfo() from the console and the app will exercise just that.

Common Mistake #2: Not Having a Dot In There

You probably have read that if you were not having a dot in your ng-model, you were doing it wrong. When it regards inheritance, that argument is often true. Scopes have a prototypal model of inheritance, typical to JavaScript, and nested scopes are common to AngularJS. Many directives create child scopes such as ngRepeat, ngIf, and ngController. When resolving a model, the lookup starts on the current scope and goes through every parent scope, all the mode to $rootScope.

But, when setting a new value, what happens depends on what kind of model (variable) nosotros want to alter. If the model is a primitive, the child scope volition only create a new model. But if the change is to a property of a model object, the lookup on parent scopes will find the referenced object and change its actual property. A new model would non exist set on the current scope, so no masking would occur:

          function MainController($scope) {   $scope.foo = 1;   $scope.bar = {innerProperty: 2}; }  angular.module('myApp', []) .controller('MainController', MainController);                  
          <div ng-controller="MainController">   <p>OUTER SCOPE:</p>   <p>{{ foo }}</p>   <p>{{ bar.innerProperty }}</p>   <div ng-if="foo"> <!— ng-if creates a new telescopic —>     <p>INNER Scope</p>     <p>{{ foo }}</p>     <p>{{ bar.innerProperty }}</p>     <push button ng-click="foo = two">Set primitive</push>     <button ng-click="bar.innerProperty = 3">Mutate object</button>   </div> </div>                  

Clicking the push button labelled "Set archaic" will set foo in the inner telescopic to ii, but volition non change foo in the outer telescopic.

Clicking the button labelled "Alter object" will change the bar property from the parent scope. Since there is no variable on the inner scope, no shadowing volition happen, and the visible value for bar volition be 3 in both scopes.

Some other manner to exercise this is to leverage the fact that the parent scopes and the root Scope are referenced from every scope. The $parent and $root objects tin exist used to access the parent telescopic and $rootScope, respectively, directly from the view. It may be a powerful way, but I am non a fan of it due to the problem with targeting a particular telescopic upwardly the stream. At that place is another manner to ready and access properties specific to a scope - using the controllerAs syntax.

Common Mistake #3: Not Using controllerAs Syntax

The alternative and nigh efficient way to assign models to use a controller object instead of the injected $scope. Instead of injecting scope, we can define models like this:

          function MainController($telescopic) {   this.foo = 1;   var that = this;   var setBar = part () {     // that.bar = {someProperty: ii};     this.bar = {someProperty: 2};   };   setBar.telephone call(this);   // there are other conventions:    // var MC = this;   // setBar.call(this); when using 'this' inside setBar() }                  
          <div>   <p>OUTER Scope:</p>   <p>{{ MC.foo }}</p>   <p>{{ MC.bar.someProperty }}</p>   <div ng-if="test1">     <p>INNER Scope</p>     <p>{{ MC.foo }}</p>     <p>{{ MC.bar.someProperty }}</p>     <button ng-click="MC.foo = three">Change MC.foo</button>     <button ng-click="MC.bar.someProperty = v">Change MC.bar.someProperty</button>   </div> </div>                  

This is much less confusing. Especially when there are many nested scopes, every bit can exist the example with nested states.

There is more than to the controllerAs syntax.

Common Mistake #4: Non Fully Utilising The controllerAs Syntax

There are a few caveats with how the controller object is exposed. It is basically an object assail the controller's scope, just like a normal model.

If you lot demand to watch a property of the controller object, you tin sentinel a function but you are non required to. Here is an example:

          function MainController($scope) {   this.title = 'Some title';   $scope.$watch(angular.bind(this, office () {     return this.title;   }), role (newVal, oldVal) {     // handle changes   }); }                  

It is easier to just do:

          part MainController($scope) {   this.title = 'Some title';   $scope.$watch('MC.title', function (newVal, oldVal) {     // handle changes   }); }                  

Meaning that also down the scope chain, you could access MC from a child controller:

          function NestedController($scope) {   if ($scope.MC && $scope.MC.championship === 'Some title') {     $scope.MC.title = 'New title';   } }                  

However, to exist able to exercise that you lot need to be consequent with the acronym you lot use for controllerAs. There are at least three ways to gear up it. Y'all already saw the showtime one:

          <div ng-controller="MainController as MC">    … </div>                  

However, if you apply ui-router, specifying a controller that way is prone to mistake. For states, controllers should be specified in the state configuration:

          athwart.module('myApp', []) .config(function ($stateProvider) {   $stateProvider   .state('main', {     url: '/',     controller: 'MainController equally MC',     templateUrl: '/path/to/template.html'   }) }). controller('MainController', function () { … });                  

There is another manner to annotate:

          (…) .state('main', {   url: '/',   controller: 'MainController',   controllerAs: 'MC',   templateUrl: '/path/to/template.html' })                  

Yous can do the aforementioned in directives:

          role AnotherController() {   this.text = 'abc'; }  function testForToptal() {   return {     controller: 'AnotherController equally AC',     template: '<p>{{ Air-conditioning.text }}</p>'   }; }  angular.module('myApp', []) .controller('AnotherController', AnotherController) .directive('testForToptal', testForToptal);                  

The other way to comment is valid too, although less curtailed:

          role testForToptal() {   return {     controller: 'AnotherController',     controllerAs: 'AC',     template: '<p>{{ AC.text }}</p>'   }; }                  

Common Mistake #5: Not Using Named Views With UI-ROUTER For Power"

The de facto routing solution for AngularJS has been, until now, the ui-router. Removed from core one-time agone, ngRoute module, was too basic for more sophisticated routing.

In that location is a new NgRouter on it'southward way, simply the authors even so consider it as well early for production. When I am writing this, the stable Athwart is 1.3.xv, and ui-router rocks.

The main reasons:

  • crawly land nesting
  • route abstraction
  • optional and required parameters

Here I will cover state nesting to avoid AngularJS errors.

Think of this as a complex yet standard use instance. There is an app, which has a homepage view and a product view. The product view has iii carve up sections: the intro, the widget, and the content. We want the widget to persist and non reload when switching between land. But the content should reload.

Consider the following HTML production alphabetize page structure:

          <body>   <header>     <!-- SOME STATIC HEADER CONTENT -->   </header>    <section class="master">     <div class="folio-content">      <div grade="row">       <div form="col-xs-12">         <section course="intro">           <h2>SOME Product SPECIFIC INTRO</h2>         </department>       </div>     </div>      <div class="row">       <div form="col-xs-3">         <section class="widget">           <!-- some widget, which should never reload -->         </section>       </div>       <div class="col-xs-9">         <department class="content">           <div class="production-content">           <h2>Production title</h2>           <bridge>Context-specific content</span>         </div>         </section>       </div>     </div>    </div>    </department>    <footer>     <!-- SOME STATIC HEADER CONTENT -->   </footer>  </trunk>                  

This is something we could get from the HTML coder, and now need to divide it into files and states. I generally get with the convention that there is an abstract Main state, which keeps the global data if needed. Use that instead of $rootScope. The Master state volition also keep static HTML that is required on every folio. I keep index.html clean.

          <!— index.html —> <body>   <div ui-view></div> </body>                  
          <!— chief.html —> <header>   <!-- SOME STATIC HEADER CONTENT --> </header>  <section course="main">   <div ui-view></div> </section>  <footer>   <!-- SOME STATIC HEADER CONTENT --> </footer>                  

Then let'south run into the production index page:

          <div class="folio-content">    <div class="row">     <div course="col-xs-12">       <department class="intro">         <div ui-view="intro"></div>       </section>     </div>   </div>    <div class="row">     <div class="col-xs-three">       <section course="widget">         <div ui-view="widget"></div>       </section>     </div>     <div course="col-xs-9">       <section class="content">         <div ui-view="content"></div>       </section>     </div>   </div>  </div>                  

As you tin come across, the product alphabetize page has iii named views. One for the intro, one for the widget, and one for the production. We meet the specs! Then now allow's gear up routing:

          role config($stateProvider) {   $stateProvider     // Main Abstruse STATE, ALWAYS ON     .state('main', {       abstruse: true,       url: '/',       controller: 'MainController as MC',       templateUrl: '/routing-demo/main.html'     })     // A SIMPLE HOMEPAGE     .state('main.homepage', {       url: '',       controller: 'HomepageController every bit HC',       templateUrl: '/routing-demo/homepage.html'     })     // THE In a higher place IS ALL GOOD, HERE IS Problem     // A Complex PRODUCT Folio     .land('main.product', {       abstruse: true,       url: ':id',       controller: 'ProductController as PC',       templateUrl: '/routing-demo/product.html',     })     // Production DEFAULT SUBSTATE     .land('main.product.index', {       url: '',       views: {         'widget': {           controller: 'WidgetController as PWC',           templateUrl: '/routing-demo/widget.html'          },         'intro': {           controller: 'IntroController as PIC',           templateUrl: '/routing-demo/intro.html'          },         'content': {           controller: 'ContentController as PCC',           templateUrl: '/routing-demo/content.html'         }       }     })     // PRODUCT DETAILS SUBSTATE     .country('main.product.details', {       url: '/details',       views: {         'widget': {           controller: 'WidgetController equally PWC',           templateUrl: '/routing-demo/widget.html'          },         'content': {           controller: 'ContentController as PCC',           templateUrl: '/routing-demo/content.html'         }       }     }); }  angular.module('articleApp', [   'ui.router' ]) .config(config);                  

That would be the first approach. Now, what happens when switching between main.product.index and chief.product.details? The content and widget get reloaded, but we only want to reload the content. This was problematic, and developers actually created routers that would support just that functionality. One of the names for this was sticky views. Fortunately, ui-router supports that out of the box with accented named view targeting.

          // A COMPLEX Product PAGE // WITH NO MORE Trouble .state('main.production', {   abstract: true,   url: ':id',   views: {     // TARGETING THE UNNAMED VIEW IN MAIN.HTML     '@main': {       controller: 'ProductController as PC',       templateUrl: '/routing-demo/product.html'      },     // TARGETING THE WIDGET VIEW IN Production.HTML     // BY DEFINING A CHILD VIEW ALREADY HERE, WE ENSURE IT DOES Not RELOAD ON CHILD STATE Modify     'widget@main.product': {       controller: 'WidgetController as PWC',       templateUrl: '/routing-demo/widget.html'      }   } }) // Product DEFAULT SUBSTATE .state('main.product.index', {   url: '',   views: {     'intro': {       controller: 'IntroController as PIC',       templateUrl: '/routing-demo/intro.html'      },     'content': {       controller: 'ContentController every bit PCC',       templateUrl: '/routing-demo/content.html'     }   } }) // Production DETAILS SUBSTATE .state('master.product.details', {   url: '/details',   views: {     'content': {       controller: 'ContentController equally PCC',       templateUrl: '/routing-demo/content.html'     }   } });                  

By moving the state definition to the parent view, which also is abstract, we can preserve the child view from reloading when switching urls which ordinarily affects that child's siblings. Of course, the widget could be a simple directive. But the point is, it could also be another complex nested state.

At that place is some other way to do this through the utilize of $urlRouterProvider.deferIntercept(), but I recollect that using state configuration is really better. If yous are interested in intercepting routes, I wrote a pocket-size tutorial on StackOverflow.

Common Mistake #half dozen: Declaring Everything In The Angular World Using Anonymous Functions

This mistake is of a lighter calibre, and is more a question of fashion than avoiding AngularJS error messages. Yous may have previously noticed that I seldom pass anonymous functions to athwart internal's declarations. I ordinarily simply define a function start and then laissez passer information technology in.

This regards more than just functions. I got this approach from reading fashion guides, especially Airbnb's and Todd Motto's. I believe there are several advantages and almost no drawbacks to it.

First of all, y'all can manipulate and mutate your functions and objects much easier if they are assigned to a variable. Secondly, the code is cleaner and tin be hands split up into files. That means maintainability. If yous don't want to pollute the global namespace, wrap every file in IIFEs. The 3rd reason is testability. Consider this example:

          'use strict';  function yoda() {    var privateMethod = role () {     // this role is not exposed   };    var publicMethod1 = part () {     // this function is exposed, only information technology's internals are not exposed     // some logic...   };    var publicMethod2 = function (arg) {     // THE Below CALL CANNOT Be SPIED ON WITH JASMINE     publicMethod1('someArgument');   };    // IF THE LITERAL IS RETURNED THIS Style, IT Tin'T BE REFERRED TO FROM Within   return {     publicMethod1: function () {       return publicMethod1();     },     publicMethod2: function (arg) {       return publicMethod2(arg);     }   }; }  angular.module('app', []) .mill('yoda', yoda);                  

So at present we could mock the publicMethod1, but why should we practice that since information technology is exposed? Wouldn't it be easier just to spy on the existing method? However, the method is actually some other office - a thin wrapper. Have a await at this arroyo:

          function yoda() {    var privateMethod = function () {     // this part is not exposed   };    var publicMethod1 = function () {     // this office is exposed, but information technology'due south internals are not exposed     // some logic...   };    var publicMethod2 = function (arg) {     // the beneath call cannot be spied on     publicMethod1('someArgument');      // Just THIS One CAN!     hostObject.publicMethod1('aBetterArgument');   };    var hostObject = {     publicMethod1: role () {       return publicMethod1();     },     publicMethod2: part (arg) {       return publicMethod2(arg);     }   };    return hostObject; }                  

This is not only most style, since in consequence the code is more reusable and idiomatic. The developer gets more than expressive power. Splitting all lawmaking into cocky-contained blocks just makes it easier.

Common Error #7: Doing Heavy Processing In Angular AKA Using Workers

In some scenarios, it may exist required to process a big array of circuitous objects by passing them through a set of filters, decorators, and finally a sorting algorithm. One use case is when the app should work offline or where the functioning of displaying data is key. And since JavaScript is unmarried-threaded, it is relatively easy to freeze the browser.

It is also easy to avoid information technology with spider web workers. There don't seem to exist any pop libraries that handle that specifically for AngularJS. It might be for the all-time though, since the implementation is piece of cake.

Showtime, let's setup the service:

          role scoringService($q) {      var scoreItems = function (items, weights) {     var deferred = $q.defer();     var worker = new Worker('/worker-demo/scoring.worker.js');     var orders = {       items: items,       weights: weights     };     worker.postMessage(orders);     worker.onmessage = office (e) {       if (eastward.data && east.data.ready) {         deferred.resolve(e.data.items);       }     };      return deferred.promise;   };   var hostObject = {     scoreItems: function (items, weights) {       return scoreItems(items, weights);     }   };    return hostObject;  }  athwart.module('app.worker') .factory('scoringService', scoringService);                  

Now, the worker:

          'use strict';  function scoringFunction(items, weights) {   var itemsArray = [];   for (var i = 0; i < items.length; i++) {     // some heavy processing     // itemsArray is populated, etc.   }    itemsArray.sort(function (a, b) {     if (a.sum > b.sum) {       render -ane;     } else if (a.sum < b.sum) {       return 1;     } else {       return 0;     }   });    return itemsArray; }  self.addEventListener('message', office (e) {   var reply = {     fix: true   };   if (e.data && eastward.information.items && e.information.items.length) {     respond.items = scoringFunction(e.data.items, east.data.weights);   }   self.postMessage(reply); }, false);                  

At present, inject the service as usual and treat scoringService.scoreItems() as you would whatsoever service method that returns a promise. The heavy processing will exist carried out on a split thread, and no harm will exist washed to the UX.

What to look out for:

  • there does not seem to exist a full general rule for how many workers to spawn. Some developers claim that 8 is a proficient number, only use an online calculator and suit yourself
  • check compatibility with older browsers
  • I run into an effect when passing the number 0 from the service to the worker. I applied .toString() on the passed belongings, and information technology worked correctly.

Common Mistake #eight: Overusing And Misunderstanding Resolves

Resolves add extra fourth dimension to the loading of the view. I believe that loftier performance of the front-end app is our main goal. It should not exist a problem to return some parts of the view while the app waits for the data from the API.

Consider this setup:

          role resolve(index, timeout) {   return {     data: office($q, $timeout) {       var deferred = $q.defer();       $timeout(function () {         deferred.resolve(panel.log('Data resolve chosen ' + index));       }, timeout);       render deferred.promise;     }   }; }  function configResolves($stateProvide) {   $stateProvider     // MAIN ABSTRACT STATE, E'er ON     .state('main', {       url: '/',       controller: 'MainController every bit MC',       templateUrl: '/routing-demo/main.html',       resolve: resolve(i, 1597)     })     // A Complex Product PAGE     .state('main.product', {       url: ':id',         controller: 'ProductController every bit PC',       templateUrl: '/routing-demo/product.html',       resolve: resolve(ii, 2584)     })     // PRODUCT DEFAULT SUBSTATE     .state('principal.product.alphabetize', {       url: '',       views: {         'intro': {           controller: 'IntroController every bit Motion picture',           templateUrl: '/routing-demo/intro.html'         },         'content': {           controller: 'ContentController as PCC',           templateUrl: '/routing-demo/content.html'         }       },       resolve: resolve(3, 987)     }); }                  

The console output volition exist:

          Data resolve called 3 Data resolve chosen one Data resolve called 2 Main Controller executed Product Controller executed Intro Controller executed                  

Which basically ways that:

  • The resolves are executed asynchronously
  • We can't rely on an order of execution (or at least demand to flex quite a bit)
  • All the states are blocked until all resolves do their affair, even if they are non abstract.

This means that earlier the user sees whatsoever output, he/she must await for all the dependencies. Nosotros need to have that data, sure, okay. If it absolutely necessary to accept it before the view, put information technology in a .run() block. Otherwise, just make the call to the service from the controller and handle the half-loaded state gracefully. Seeing work in progress - and the controller is already executed, so it really is progress - is better than having the app stall.

Common Mistake #9: Non Optimizing The App - Three Examples

a) Causing also many assimilate loops, such as attaching sliders to models

This is a general problem that can result in AngularJS errors, but I will talk over information technology at the example of sliders. I was using this slider library, angular range slider, considering I needed the extended functionality. That directive has this syntax in the minimal version:

          <body ng-controller="MainController as MC">   <div range-slider      min="0"      max="MC.maxPrice"      pin-handle="min"      model-max="MC.price"   >   </div> </body>                  

Consider the following lawmaking in the controller:

          this.maxPrice = '100'; this.price = '55';  $scope.$spotter('MC.price', part (newVal) {   if (newVal || newVal === 0) {     for (var i = 0; i < 987; i++) {       console.log('ALL YOUR BASE ARE Belong TO U.s.');     }   } });                  

And so that works boring. The casual solution would be to ready a timeout on the input. Simply that is not always handy, and sometimes nosotros don't actually want to filibuster the bodily model change in all cases.

And so we will add a temporary model bound to change the working model on timeout:

          <body ng-controller="MainController as MC">   <div range-slider      min="0"      max="MC.maxPrice"      pin-handle="min"      model-max="MC.priceTemporary"   >   </div> </trunk>                  

and in the controller:

          this.maxPrice = '100'; this.price = '55'; this.priceTemporary = '55';  $scope.$watch('MC.toll', function (newVal) {   if (!isNaN(newVal)) {     for (var i = 0; i < 987; i++) {       console.log('ALL YOUR BASE ARE Belong TO US');     }   } });  var timeoutInstance; $scope.$watch('MC.priceTemporary', part (newVal) {   if (!isNaN(newVal)) {     if (timeoutInstance) {       $timeout.cancel(timeoutInstance);     }      timeoutInstance = $timeout(function () {       $scope.MC.price = newVal;     }, 144);        } });                  

b) Not using $applyAsync

AngularJS does not have a polling machinery to telephone call $digest(). It is only executed considering we use the directives (due east.g. ng-click, input), services ($timeout, $http), and methods ($watch) which evaluate our code and telephone call a digest after.

What .$applyAsync() does is information technology delays the resolution of expressions until the next $digest() cycle, which is triggered afterwards a 0 timeout, which really is ~10ms.

There are two ways to use applyAsync now. An automated way for $http requests, and a manual way for the rest.

To make all http requests that return in around the same fourth dimension resolve in 1 digest, do:

          mymodule.config(function ($httpProvider) {   $httpProvider.useApplyAsync(true); });                  

The transmission fashion shows how it really works. Consider some function that runs on the callback to a vanilla JS effect listener or a jQuery .click(), or some other external library. After it executes and changes models, if you didn't already wrap information technology in an $apply() you demand to telephone call $scope.$root.$assimilate() ($rootScope.$digest()), or at to the lowest degree $scope.$assimilate(). Otherwise, y'all volition see no modify.

If y'all do that multiple times in one catamenia, information technology might start running slow. Consider calling $scope.$applyAsync() on the expressions instead. It will set just call one digest cycle for all of them.

c) Doing heavy processing of images

If yous feel bad performance, you can investigate the reason by using the Timeline from Chrome Programmer Tools. I will write more near this tool in mistake #17. If your timeline graph is dominated with the color greenish after recording, your functioning issues may be related to processing of images. This is not strictly related to AngularJS, only may happen on tiptop of AngularJS performance problems (which would be by and large xanthous on the graph). As front-terminate engineers, we need to recall about the complete end project.

Have a moment to assess:

  • Do you utilise parallax?
  • Do you accept several layers of content overlapping ane some other?
  • Practise you movement your images effectually?
  • Exercise you lot scale images (east.1000. with groundwork-size)?
  • Do you lot resize images in loops, and mayhap cause assimilate loops on resize?

If y'all answered "yeah" to at least three of the higher up, consider easing it. Peradventure you can serve diverse prototype sizes and not resize at all. Mayhap yous could add together the "transform: translateZ(0)" force GPU processing hack. Or utilise requestAnimationFrame for handlers.

Mutual Mistake #x: jQuerying It - Detached DOM Tree

Many times you probably hear that information technology's not recommended to use jQuery with AngularJS, and that it should be avoided. It is imperative to empathise the reason behind these statements. There are at least three reasons, as far as I can see, but none of them are actual blockers.

Reason ane: When you execute jQuery code, you need to phone call $digest() yourself. For many cases, there is an AngularJS solution which is tailored for AngularJS and can be of better use inside Angular than jQuery (e.g. ng-click or the outcome system).

Reason 2: The method of idea about building the app. If you have been adding JavaScript to websites, which reload when navigating, you did not have to worry almost retentivity consumption besides much. With single-page apps, you do accept to worry. If yous don't clean up, users who spend more than a few minutes on your app may feel growing functioning bug.

Reason 3: Cleaning up is not actually the easiest thing to do and clarify. There is no fashion to call a garbage collector from the script (in the browser). You may end up with detached DOM copse. I created an example (jQuery is loaded in index.html):

          <section>   <test-for-toptal></test-for-toptal>   <button ng-click="MC.removeDirective()">remove directive</push button> </department>                  
          function MainController($rootScope, $telescopic) {   this.removeDirective = part () {     $rootScope.$emit('destroyDirective');   }; }  function testForToptal($rootScope, $timeout) {   return {     link: role (telescopic, element, attributes) {        var destroyListener = $rootScope.$on('destroyDirective', function () {         scope.$destroy();       });        // adding a timeout for the DOM to get ready       $timeout(office () {         scope.toBeDetached = element.find('p');       });        scope.$on('$destroy', office () {         destroyListener();         element.remove();       });     },     template: '<div><p>I AM DIRECTIVE</p></div>'   }; }  angular.module('app', []) .controller('MainController', MainController) .directive('testForToptal', testForToptal);                  

This is a simple directive that outputs some text. There is a button below it, which volition simply destroy the directive manually.

So when the directive is removed, there remains a reference to the DOM tree in scope.toBeDetached. In chrome dev tools, if you access the tab "profiles" and then "accept heap snapshot", you will see in the output:

You can live with a few, but it is bad if you have a ton. Especially if for some reason, like in the example, you lot store it on the telescopic. The whole DOM volition exist evaluated on every digest. The problematic detached DOM tree is the one with 4 nodes. So how tin this exist solved?

          scope.$on('$destroy', function () {    // setting this model to nothing   // volition solve the problem.   scope.toBeDetached = zero;    destroyListener();   element.remove(); });                  

The detached DOM tree with 4 entries is removed!

In this example, the directive uses the same telescopic, and stores the DOM element on the telescopic. It was easier for me to demonstrate it that mode. It does not always get that bad, every bit you could store it in a variable. However, information technology would nevertheless accept up retention if any closure that had referenced that variable or whatever other from the same function telescopic lived on.

Common Fault #11: Overusing Isolated Scope

Whenever you need a directive that you lot know will be used in a single place, or which you don't expect to conflict with any environment information technology is used in, at that place is no need to use isolated telescopic. Lately, there is a trend to create reusable components, simply did you know that cadre angular directives don't employ isolated scope at all?

There are ii main reasons: yous can't employ two isolated scope directives to an chemical element, and yous may encounter issues with nesting / inheritance / result processing. Particularly regarding transclusion - the furnishings may not be what you expect.

So this would fail:

          <p isolated-telescopic-directive another-isolated-telescopic-directive ng-if="MC.quux" ng-repeat="q in MC.quux"></p>                  

And even if you lot use merely one directive, yous volition notice that neither the isolated scope models nor events broadcasted in isolatedScopeDirective will not be available to AnotherController. That being lamentable, you tin flex and utilise transclusion magic to make it piece of work - but for most utilise cases, at that place is no need to isolate.

          <p isolated-scope-directive ng-if="MC.quux" ng-repeat="q in MC.quux">   <div ng-controller="AnotherController">     … the isolated scope is non available here, look: {{ isolatedModel }}   </div> </p>                  

So, two questions now:

  1. How can you process parent scope models in a aforementioned-telescopic directive?
  2. How tin can you instantiate new model values?

In that location are two means, in both of them you pass values to attributes. Consider this MainController:

          function MainController($interval) {   this.foo = {     bar: ane   };   this.baz = 1;   var that = this;   $interval(function () {     that.foo.bar++;   }, 144);    $interval(function () {     that.baz++;   }, 144);    this.quux = [one,ii,three]; }                  

That controls this view:

          <body ng-controller="MainController every bit MC">    <div class="cyan-surface">     <h1 style="font-size: 21px;">Attributes exam</h1>     <examination-directive watch-attribute="MC.foo" observe-attribute="current index: {{ MC.baz }}"></exam-directive>   </div>  </body>                  

Notice that "picket-attribute" is not interpolated. Information technology all works, due to JS magic. Here is the directive definition:

          function testDirective() {   var postLink = function (telescopic, chemical element, attrs) {     scope.$sentinel(attrs.watchAttribute, function (newVal) {       if (newVal) {         // take a look in the console         // nosotros can't use the aspect directly         panel.log(attrs.watchAttribute);          // the newVal is evaluated, and it can be used         scope.modifiedFooBar = newVal.bar * 10;       }     }, truthful);      attrs.$find('observeAttribute', function (newVal) {       telescopic.observed = newVal;     });   };    return {     link: postLink,     templateUrl: '/attributes-demo/test-directive.html'   }; }                  

Notice that attrs.watchAttribute is passed into scope.$spotter() without the quotation marks! That ways what was actually passed to $watch was the string MC.foo! It does piece of work, still, because whatsoever cord passed into $watch() gets evaluated confronting the scope and MC.foo is available on the scope. That is too the most mutual way that attributes are watched in AngularJS core directives.

See the code on github for the template, and wait into $parse and $eval for even more than awesomeness.

Common Mistake #12: Not Cleaning Up After Yourself - Watchers, Intervals, Timeouts And Variables

AngularJS does some work on your behalf, but non all. The post-obit need to be manually cleaned up:

  • Whatsoever watchers that are non jump to the current scope (e.1000. bound to $rootScope)
  • Intervals
  • Timeouts
  • Variables referencing DOM in directives
  • Dodgy jQuery plugins, east.g. those that don't accept handlers reacting to the JavaScript $destroy event

If you don't do that manually, you will encounter unexpected behaviour and retentivity leaks. Fifty-fifty worse - these will not be instantly visible, only they will creep up eventually. Murphy's police force.

Amazingly, AngularJS provides handy means to deal with all of those:

          function cleanMeUp($interval, $rootScope, $timeout) {   var postLink = part (scope, element, attrs) {     var rootModelListener = $rootScope.$watch('someModel', function () {       // practice something     });      var myInterval = $interval(role () {       // exercise something in intervals     }, 2584);      var myTimeout = $timeout(function () {       // defer some action here     }, 1597);      scope.domElement = element;      $timeout(role () {       // calling $destroy manually for testing purposes       scope.$destroy();     }, 987);      // here is where the cleanup happens     scope.$on('$destroy', function () {       // disable the listener       rootModelListener();        // abolish the interval and timeout       $interval.cancel(myInterval);       $timeout.abolish(myTimeout);        // nullify the DOM-spring model       scope.domElement = nix;     });      element.on('$destroy', function () {       // this is a jQuery upshot       // clean up all vanilla JavaScript / jQuery artifacts here        // respectful jQuery plugins accept $destroy handlers,       // that is the reason why this event is emitted...       // follow the standards.     });    };                  

Notice the jQuery $destroy result. It is called like the AngularJS i, merely it is handled separately. Scope $watchers volition not react to the jQuery event.

Common Mistake #thirteen: Keeping Also Many Watchers

This should be quite elementary now. There is 1 thing to sympathise hither: $assimilate(). For every binding {{ model }}, AngularJS creates a watcher. On every digest stage, each such binding is evaluated and compared against the previous value. That is called dirty-checking, and that'south what $digest does. If the value changed since the final cheque, the watcher callback is fired. If that watcher callback modifies a model ($scope variable), a new $digest cycle is fired (upwards to a maximum of 10) when an exception is thrown.

Browsers don't have problems even with thousands of bindings, unless the expressions are complex. The common answer for "how many watchers are ok to have" is 2000.

So, how can we limit the number of watchers? Past not watching telescopic models when we don't expect them to change. It is fairly easy onwards from AngularJS 1.3, since one-time bindings are in core now.

          <li ng-repeat="particular in ::vastArray">{{ ::item.velocity }}</li>                  

Later vastArray and item.velocity are evaluated in one case, they volition never change again. You can still utilise filters to the array, they will work but fine. Information technology is just that the array itself volition not exist evaluated. In many cases, that is a win.

Mutual Mistake #14: Misunderstanding The Digest

This AngularJS mistake was already partly covered in mistakes 9.b and in 13. This is a more thorough explanation. AngularJS updates DOM equally a result of callback functions to watchers. Every binding, that is the directive {{ someModel }} sets upwards watchers, merely watchers are likewise set for many other directives similar ng-if and ng-repeat. Just accept a look at the source code, it is very readable. Watchers can also be gear up manually, and y'all have probably done that at least a few times yourself.

$watch()ers are bound to scopes. $Watchers tin can take strings, which are evaluated against the scope that the $watch() was bound to. They can too evaluate functions. And they also take callbacks. And so, when $rootScope.$assimilate() is called, all the registered models (that is $scope variables) are evaluated and compared confronting their previous values. If the values don't match, the callback to the $watch() is executed.

It is important to understand that even though a model's value was changed, the callback does not fire until the next digest phase. It is chosen a "stage" for a reason - it can consist of several digest cycles. If but a watcher changes a scope model, another digest cycle is executed.

But $digest() is not polled for. It is chosen from core directives, services, methods, etc. If you change a model from a custom part that does non phone call .$use, .$applyAsync, .$evalAsync, or anything else that eventually calls $digest(), the bindings will non be updated.

Past the way, the source lawmaking for $assimilate() is actually quite complex. It is nevertheless worth reading, as the hilarious warnings make up for it.

Common Mistake #15: Not Relying On Automation, Or Relying On It Too Much

If yous follow the trends within front end cease development and are a bit lazy - like me - and then you probably endeavour to not practice everything by hand. Keeping track of all your dependencies, processing sets of files in different means, reloading the browser subsequently every file relieve - there is a lot more to developing than merely coding.

So you may exist using bower, and peradventure npm depending on how yous serve your app. In that location is a chance that yous may be using grunt, gulp, or brunch. Or bash, which also is cool. In fact, you lot may accept started your latest projection with some Yeoman generator!

This leads to the question: do you empathize the whole process of what your infrastructure really does? Exercise y'all need what you have, peculiarly if yous just spent hours trying to prepare your connect webserver livereload functionality?

Take a second to assess what you need. All those tools are simply hither to assist you, in that location is no other reward for using them. The more experienced developers I talk to tend to simplify things.

Mutual Error #16: Not Running The Unit of measurement Tests In TDD Mode

Tests will not brand your code gratis of AngularJS error messages. What they volition do is assure that your team doesn't encounter regression issues all the fourth dimension.

I am writing specifically nearly unit of measurement tests hither, non because I feel they are more important than e2e tests, but because they execute much faster. I must admit that the procedure I am about to describe is a very pleasurable one.

Examination Driven Development every bit an implementation for e.grand. gulp-karma runner, basically runs all your unit tests on every file save. My favorite mode to write tests is, I but write empty assurances first:

          draw('some module', function () {   information technology('should call the name-it service…', office () {     // leave this empty for now   });   ... });                  

Afterwards that, I write or refactor the actual code, then I come back to the tests and fill in the assurances with bodily test code.

Having a TDD job running in a final speeds up the process by well-nigh 100%. Unit of measurement tests execute in a matter of a few seconds, fifty-fifty if y'all have a lot of them. Just salvage the test file and the runner volition pick it upwards, evaluate your tests, and provide feedback instantly.

With e2e tests, the process is much slower. My advice - carve up e2e tests upward into test suites and just run one at a fourth dimension. Protractor has support for them, and beneath is the lawmaking I employ for my test tasks (I similar gulp).

          'utilize strict';  var gulp = require('gulp'); var args = crave('yargs').argv; var browserSync = require('browser-sync'); var karma = require('gulp-karma'); var protractor = require('gulp-protractor').protractor; var webdriverUpdate = require('gulp-protractor').webdriver_update;  function examination() {   // Be sure to return the stream   // Notation: Using the fake './foobar' and so as to run the files   // listed in karma.conf.js INSTEAD of what was passed to   // gulp.src !   render gulp.src('./foobar')     .pipe(karma({       configFile: 'test/karma.conf.js',       action: 'run'     }))     .on('error', function(err) {       // Make certain failed tests cause gulp to exit not-zero       // console.log(err);       this.emit('end'); //instead of erroring the stream, end it     }); }  function tdd() {   return gulp.src('./foobar')     .pipage(karma({       configFile: 'test/karma.conf.js',       action: 'start'     }))     .on('error', role(err) {       // Brand sure failed tests cause gulp to exit non-goose egg       // console.log(err);       // this.emit('cease'); // not ending the stream here     }); }  office runProtractor () {    var argument = args.suite || 'all';      // NOTE: Using the false './foobar' and so as to run the files   // listed in protractor.conf.js, instead of what was passed to   // gulp.src   return gulp.src('./foobar')     .pipe(protractor({       configFile: 'test/protractor.conf.js',       args: ['--suite', argument]     }))     .on('error', function (err) {       // Make sure failed tests cause gulp to exit not-zippo       throw err;     })     .on('stop', function () {       // Shut browser sync server       browserSync.exit();     }); }  gulp.task('tdd', tdd); gulp.task('test', exam); gulp.chore('test-e2e', ['webdriver-update'], runProtractor); gulp.job('webdriver-update', webdriverUpdate);                  

A - chrome breakpoints

Chrome dev tools allow you to betoken at a specific place in any of the files loaded into the browser, pause code execution at that point, and let you interact with all the variables available from that point. That is a lot! That functionality does not require you lot to add any code at all, everything happens in the dev tools.

Not only yous get access to all the variables, you as well see the call stack, print stack traces, and more than. You can even configure information technology to piece of work with minified files. Read about it hither.

At that place are other ways you can get similar run-time admission, e.thou. by adding console.log() calls. But breakpoints are more than sophisticated.

AngularJS also allows you lot to access scope through DOM elements (equally long every bit debugInfo is enabled), and inject bachelor services through the console. Consider the following in the console:

          $(document.body).telescopic().$root                  

or signal at an chemical element in the inspector, and then:

          $($0).scope()                  

Even if debugInfo is non enabled, yous can do:

          angular.reloadWithDebugInfo()                  

And have it available afterwards reload:

To inject and interact with a service from the panel, endeavor:

          var injector = $(document.torso).injector(); var someService = injector.get('someService');                  

B - chrome timeline

Another neat tool that comes with dev tools is the timeline. That will allow you to record and analyse your app's live performance as y'all are using information technology. The output shows, amidst others, retentiveness usage, frame charge per unit, and the autopsy of the dissimilar processes that occupy the CPU: loading, scripting, rendering, and painting.

If y'all experience that your app'southward performance degrades, you volition most likely be able to notice the crusade for that through the timeline tab. Just record your actions which led to performance issues and see what happens. As well many watchers? You will run into yellowish bars taking a lot of space. Memory leaks? You tin see how much retentiveness was consumed over time on a graph.

A detailed description: https://developer.chrome.com/devtools/docs/timeline

C - inspecting apps remotely on iOS and Android

If you are developing a hybrid app or a responsive web app, you can access your device's console, DOM tree, and all other tools bachelor either through Chrome or Safari dev tools. That includes the WebView and UIWebView.

Start, start your web server on host 0.0.0.0 and so that information technology is accessible from your local network. Enable web inspector in settings. So connect your device to your desktop and access your local evolution page, using your automobile's ip instead of the regular "localhost". That is all it takes, your device should now exist available to y'all from your desktop's browser.

Hither are the detailed instructions for Android And for iOS, unofficial guides are to exist found easily through google.

I recently had some absurd experience with browserSync. Information technology works in a similar way to livereload, just it also really syncs all browsers that are viewing the aforementioned page through browserSync. That includes user interaction such equally scrolling, clicking on buttons, etc. I was looking at the iOS app's log output while controlling the page on the iPad from my desktop. It worked nicely!

Common Fault #xviii: Not Reading The Source Code On The NG-INIT Example

Ng-init, from the sound of it, should exist similar to ng-if and ng-repeat, right? Did you ever wonder why in that location is a annotate in the docs that information technology should non be used? IMHO that was surprising! I would await the directive to initialize a model. That's as well what it does, but… it is implemented in a different mode, that is, it does not picket the attribute value. Y'all don't demand to scan through AngularJS source lawmaking - let me bring it to y'all:

          var ngInitDirective = ngDirective({   priority: 450,   compile: function() {     return {       pre: function(scope, element, attrs) {         scope.$eval(attrs.ngInit);       }     };   } });                  

Less than you would expect? Quite readable, also the awkward directive syntax, isn't it? The sixth line is what it is all about.

Compare it to ng-evidence:

          var ngShowDirective = ['$animate', function($animate) {   render {     restrict: 'A',     multiElement: true,     link: function(scope, element, attr) {       scope.$watch(attr.ngShow, function ngShowWatchAction(value) {         // we're adding a temporary, blitheness-specific course for ng-hide since this way         // we can command when the element is really displayed on screen without having         // to have a global/greedy CSS selector that breaks when other animations are run.         // Read: https://github.com/athwart/athwart.js/bug/9103#issuecomment-58335845         $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {           tempClasses: NG_HIDE_IN_PROGRESS_CLASS         });       });     }   }; }];                  

Once more, the sixth line. In that location is a $picket there, that'south what makes this directive dynamic. In the AngularJS source code, a large part of all the lawmaking are comments that describe code that was mostly readable from the beginning. I believe it is a corking way to learn about AngularJS.

Conclusion

This guide roofing almost common AngularJS mistakes is nearly twice equally long as the other guides. It turned out that way naturally. The need for high quality JavaScript front end engineers is very loftier. AngularJS is and then hot right now, and it has been property a stable position amid the most pop development tools for a few years. With AngularJS two.0 on the way, it will probably dominate for years to come.

What is great nearly front-finish development is that it is very rewarding. Our work is visible instantly, and people interact straight with the products nosotros deliver. The time spent learning JavaScript, and I believe nosotros should focus on the JavaScript language, is a very skillful investment. Information technology is the language of the Internet. The competition is super stiff! In that location is ane focus for u.s.a. - user experience. To be successful, we need to embrace everything.

Source lawmaking used in these examples can be downloaded from GitHub. Feel complimentary to download information technology and get in your own.

I wanted to requite credits to four publishing developers that inspired me the near:

  • Ben Nadel
  • Todd Motto
  • Pascal Precht
  • Sandeep Panda

I also wanted to thank all the smashing people on FreeNode #angularjs and #javascript channels for many excellent conversations, and continuous support.

And finally, always remember:

          // when in incertitude, comment information technology out! :)                  

Source: https://www.toptal.com/angular-js/top-18-most-common-angularjs-developer-mistakes

Posted by: goodwinbutenway.blogspot.com

0 Response to "How To Call Function In Angularjs Service"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel