Sunday, 30 July 2017

Angular JS: Understanding service types (Provider, Factory, Services)

Angular comes with different types of services. Each one with its own use cases.
Something important that you have to keep in mind is that the services are always singleton, it doesn’t matter which type you use. This is the desired behavior.
NOTE: A singleton is a design pattern that restricts the instantiation of a class to just one object. Every place where we inject our service, will use the same instance.

Provider

Provider is the parent of almost all the other services (all but constant) and it is also the most complex but more configurable one.
Let’s see a basic example:
app.provider('foo', function() {

  return {
    
    $get: function() {
      var thisIsPrivate = "Private";
      function getPrivate() {
        return thisIsPrivate;
      }
  
      return {
        variable: "This is public",
        getPrivate: getPrivate
      };
    } 
    
  };

});
provider on its simplest form, just needs to return a function called $get which is what we inject on the other components. So if we have a controller and we want to inject this foo provider, what we inject is the $get function of it.
Why should we use a provider when a factory is much simple? Because we can configure a provider in the config function. We can do something like this:
app.provider('foo', function() {
  
  var thisIsPrivate = "Private";

  return {
    
    setPrivate: function(newVal) {
      thisIsPrivate = newVal; 
    },
    
    $get: function() {
      function getPrivate() {
        return thisIsPrivate;
      }
  
      return {
        variable: "This is public",
        getPrivate: getPrivate
      };
    } 
    
  };

});

app.config(function(fooProvider) {
  fooProvider.setPrivate('New value from config');
});
Here we moved the thisIsPrivate outside our $get function and then we created a setPrivate function to be able to change thisIsPrivate in a config function. Why do we need to do this? Won’t it be easier to just add the setter in the $get? This has a different purpose.
Imagine we want to create a generic library to manage our models and make some REST petitions. If we hardcode the endpoints URLs, we are not making it any generic, so the idea is to be able to configure those URLs and to do so, we create a provider and we allow those URLs to be configured on a config function.
Notice that we have to put nameProvider instead of just name in our config function. To consume it, we just need to use name.
Seeing this we realize that we already configured some services in our applications, like $routeProvider and $locationProvider, to configure our routes and html5mode respectively.
Providers have two different places to make injections, on the provider constructor and on the $get function. On the provider constructor we can only inject other providers and constants (is the same limitation as the config function). On the $get function we can inject all but other providers (but we can inject other provider’s $get function).
Remember: To inject a provider you use: name + ‘Provider’ and to inject its $get function you just use name

Try it


Factory

Provider are good, they are quite flexible and complex. But what if we only want its $getfunction? I mean, no configuration at all. Well, in that cases we have the factory. Let’s see an example:
Example:
app.factory('foo', function() {
  var thisIsPrivate = "Private";
  function getPrivate() {
    return thisIsPrivate;
  }
  
  return {
    variable: "This is public",
    getPrivate: getPrivate
  };
});

// or..

app.factory('bar', function(a) {
  return a * 2;
});
As you see, we moved our provider $get function into a factory so we have what we had on the first provider example but with a much simpler syntax. In fact, internally a factory is a provider with only the $get function.
As I said before, all types are singleton, so if we modify foo.variable in one place, the other places will have that change too.
We can inject everything but providers on a factory and we can inject it everywhere except on the provider constructor and config functions.

Try it


Value

Factory is good, but what if I just want to store a simple value? I mean, no injections, just a simple value or object. Well angular has you covered with the value service:
Example:
app.value('foo', 'A simple value');
Internally a value is just a factory. And since it is a factory the same injection rules applies, AKA can’t be injected into provider constructor or config functions.

Try it


Service

So having the complex provider, the more simple factory and the value services, what is the service service? Let’s see an example first:
Example:
app.service('foo', function() {
  var thisIsPrivate = "Private";
  this.variable = "This is public";
  this.getPrivate = function() {
    return thisIsPrivate;
  };
});
The service service works much the same as the factory one. The difference is simple: The factory receives a function that gets called when we create it and the service receives a constructor function where we do a new on it (actually internally is uses Object.create instead of new).
In fact, it is the same thing as doing this:
app.factory('foo2', function() {
  return new Foobar();
});


function Foobar() {
  var thisIsPrivate = "Private";
  this.variable = "This is public";
  this.getPrivate = function() {
    return thisIsPrivate;
  };
}
Foobar is a constructor function and we instantiate it in our factory when angular processes it for the first time and then it returns it. Like the service, Foobar will be instantiated only once and the next time we use the factory it will return the same instance again.
If we already have the class and we want to use it in our service we can do that like the following:
app.service('foo3', Foobar);
If you’re wondering, what we did on foo2 is actually what angular does with services internally. That means that service is actually a factory and because of that, same injection rules applies.

Try it


Constant

Then, you’re expecting me to say that a constant is another subtype of provider like the others, but this one is not. A constant works much the same as a value as we can see here:
Example:
app.constant('fooConfig', {
  config1: true,
  config2: "Default config2"
});
So… what’s the difference then? A constant can be injected everywhere and that includes provider constructor and config functions. That is why we use constant services to create default configuration for directives, because we can modify those configuration on our config functions.
You are wondering why it is called constant if we can modify it and well that was a design decision and I have no idea about the reasons behind it.

Try it


Bonus 1: Decorator

So you decided that the foo service I sent to you lacks a greet function and you want it. Will you modify the factory? No! You can decorate it:
app.config(function($provide) {
  $provide.decorator('foo', function($delegate) {
    $delegate.greet = function() {
      return "Hello, I am a new function of 'foo'";
    };
    
    return $delegate;
  });
});
$provide is what Angular uses internally to create all the services. We can use it to create new services if we want but also to decorate existing services. $provide has a method called decorator that allows us to do that. decorator receives the name of the service and a callback function that receives a $delegate parameter. That $delegate parameter is our original service instance.
Here we can do what we want to decorate our service. In our case, we added a greet function to our original service. Then we return the new modified service.
Now when we consume it, it will have the new greet function as you will see in the Try it.
The ability to decorate services comes in handy when we are consuming 3rd party services and we want to decorate it without having to copy it in our project and then doing there the modifications.
Note: The constant service cannot be decorated.

Try it


Bonus 2: Creating new instances

Our services are singleton but we can create a singleton factory that creates new instances. Before you dive deeper, keep in mind that having singleton services is the way to go and we don’t want to change that. Said that, in the rare cases you need to generate new instances, you can do that like this:
// Our class
function Person( json ) {
  angular.extend(this, json);
}

Person.prototype = {
  update: function() {
    // Update it (With real code :P)
    this.name = "Dave";
    this.country = "Canada";
  }
};

Person.getById = function( id ) {
  // Do something to fetch a Person by the id
  return new Person({
    name: "Jesus",
    country: "Spain"
  });
};

// Our factory
app.factory('personService', function() {
  return {
    getById: Person.getById
  };
});
Here we create a Person object which receives some json to initialize the object. Then we created a function in our prototype (functions in the prototype are for the instances of the Person) and a function directly in Person (which is like a class function).
So we have a class function that will create a new Person object based on the id that we provide (well, it will in real code) and every instance is able to update itself. Now we just need to create a service that will use it.
Every time we call personService.getById we are creating a new Person object, so you can use this service in different controllers and even when the factory in a singleton, it generates new objects.
Kudos to Josh David Miller for his example.

Try it

Conclusion

Services are one of the coolest features of Angular. We have a lot of ways to create them, we just need to pick the correct one for our use cases and implement it.

Angular JS: Removing the unneeded watches

Having too many $watch can create performance issues for webpages, especially on mobile devices. This post will explain how to remove extraneous $watch and accelerate your application!
Any $watch can be disabled when it is no longer needed. Thus, we have the freedom to choose when to remove a $watch from the $watch list.
Let’s see an example:
File: app.js
app = angular.module('app', []);

app.controller('MainCtrl', function($scope) {
  $scope.updated = 0;
  
  $scope.stop = function() {
    textWatch();
  };
  
  var textWatch = $scope.$watch('text', function(newVal, oldVal) {
    if (newVal === oldVal) { return; }
    $scope.updated++;
  });
});
File: index.html
<body ng-controller="MainCtrl">
  <input type="text" ng-model="text" /> {{updated}} times updated.
  <button ng-click="stop()">Stop count</button>
</body>

Try it


The $watch function itself returns a function which will unbind the $watch when called. So, when the $watch is no longer needed, we simply call the function returned by $watch.
How can this be useful for bigger applications with hundreds to thousands of $watch?

A page made with static data

Let’s imagine that we are building a page for a conference that lists all the sessions on a certain day. This page could look like this:
File: app.js
app.controller('MainCtrl', function($scope) {
  $scope.sessions = [...];

  $scope.likeSession = function(session) {
  // Like the session
  }
});
File: index.html
<ul>
  <li ng-repeat="session in sessions">
    <div class="info">
      {{session.name}} - {{session.room}} - {{session.hour}} - {{session.speaker}}
    </div>
    <div class="likes">
      {{session.likes}} likes! <button ng-click="likeSession(session)">Like it!</button>
    </div>
  </li>
</ul>
Imagine that this is a big conference, and one day has 30 sessions. How many $watch are there? There are five per session, plus one for the ng-repeat. That makes 151 $watch. What’s the problem with this? Every time the user “likes” a session, Angular is going to check if the name of the session has changed (and will do the same with the other bindings as well).
The problem is that all of our data, with the exception of the likes, are static. Isn’t that a waste of resources? We are 100% sure that our data are not going to change, so, why should Angular check if they have changed?
The solution is simple. We unbind every $watch that is never going to detect a change. These $watch are important during the first run, in which our DOM is updated with the static information, but after that, they are watching a constant for changes, which is a clear waste of resources.
You convinced me! How can we approach this? Luckily for us, there is a guy who asked himself this question before us and created a set of directives that does the job for us: Bindonce.

Bindonce

Bindonce is a set of directives meant for bindings that are not going to change while the user is on a page. That sounds like a perfect match for our application.
Let’s rewrite our view:
File: index.html
<ul>
  <li bindonce ng-repeat="session in sessions">
    <div class="info">
      <span bo-text="session.name"></span> -
      <span bo-text="session.room"></span> -
      <span bo-text="session.hour"></span> -
      <span bo-text="session.speaker"></span>
    </div>
    <div class="likes">
      {{session.likes}} likes! <button ng-click="likeSession(session)">Like it!</button>
    </div>
  </li>
</ul>
For this to work we need to import bindonce into our app (and load the library after Angular):
File: app.js
app = angular.module('app', ['pasvaz.bindonce']);
We changed our interpolations ({{ ... }}) to bo-text. This directive binds our model and waits until the DOM is updated to unbind the $watch. This way, the data will be on screen but without any $watch.
To make this happen, we need to set the bindonce directive in the parent, so it will know when the data is ready (in this case, the session) so the children directives like bo-text will know when they can actually unbind the $watch.
The result of this is one $watch per session instead of five. That makes 31 $watch instead of 151. That means that with a proper use of bindonce we can potentially reduce the number of watches in our application.

Conclusion

While premature optimization should be avoided, this library could help an application that is suffering from a performance bottleneck.
There are a lot more directives in bindonce, so I encourage you to check them out! List of directives

Angular JS: Watch how the apply runs a digest

Angular users want to know how data-binding works. There is a lot of vocabulary around this: $watch$apply$digestdirty-checking… What are they and how do they work? Here I want to address all those questions, which are well addressed in the documentation, but I want to glue some pieces together to address everything in here, but keep in mind that I want to do that in a simple way. For more technical issues, check the source.
Let’s start from the beginning.

The browser events-loop and the Angular.js extension

Our browser is waiting for events, for example the user interactions. If you click on a button or write into an input, the event’s callback will run inside Javascript and there you can do any DOM manipulation, so when the callback is done, the browser will make the appropiate changes in the DOM.
Angular extends this events-loop creating something called angular context (remember this, it is an important concept). To explain what this context is and how it works we will need to explain more concepts.

The $watch list

Every time you bind something in the UI you insert a $watch in a $watch list. Imagine the $watch as something that is able to detect changes in the model it is watching (bear with me, this will be clear soon). Imagine you have this:
File: index.html
User: <input type="text" ng-model="user" />
Password: <input type="password" ng-model="pass" />
Here we have $scope.user, which is bound to the first input, and we have $scope.pass, which is bound to the second one. Doing this we add two $watch to the $watch list.
File: controllers.js
app.controller('MainCtrl', function($scope) {
  $scope.foo = "Foo";
  $scope.world = "World";
});
File: index.html
Hello, {{ World }}
Here, even though we have two things attached to the $scope, only one is bound. So in this case we only created one $watch.
File: controllers.js
app.controller('MainCtrl', function($scope) {
  $scope.people = [...];
});
File: index.html
<ul>
  <li ng-repeat="person in people">
    {{person.name}} - {{person.age}}
  </li>
</ul>
How many $watch are created here? Two for each person (for name and age) in people plus one for the ng-repeat. If we have 10 people in the list it will be (2 * 10) + 1, AKA 21 $watch.
So, everything that is bound in our UI using directives creates a $watch. Right, but when are those $watch created?
When our template is loaded, AKA in the linking phase, the compiler will look for every directive and creates all the $watch that are needed. This sounds good, but… now what?

$digest loop

Remember the extended event-loop I talked about? When the browser receives an event that can be managed by the angular context the $digest loop will be fired. This loop is made from two smaller loops. One processes the $evalAsync queue and the other one processes the $watch list, which is the subject of this article.
What is that process about? The $digest will loop through the list of $watch that we have, asking this:
  • Hey $watch, what is your value?
    • It is 9
  • Alright, has it changed?
    • No, sir.
  • (nothing happens with this one, so it moves to the next)
  • You, what is your value?
    • It is Foo.
  • Has it changed?
    • Yes, it was Bar.
  • (good, we have a DOM to be updated)
  • This continues until every $watch has been checked.
This is the dirty-checking. Now that all the $watch have been checked there is something else to ask: Is there any $watch that has been updated? If there is at least one of them that has changed, the loop will fire again until all of the $watch report no changes. This is to ensure that every model is clean. Have in mind that if the loop runs more than 10 times, it will throw an exception to prevent infinite loops.
When the $digest loop finishes, the DOM makes the changes.
Example:
File: controllers.js
app.controller('MainCtrl', function() {
  $scope.name = "Foo";

  $scope.changeFoo = function() {
    $scope.name = "Bar";
  }
});
File: index.html
{{ name }}
<button ng-click="changeFoo()">Change the name</button>
Here we have only one $watch because ng-click doesn’t create any watches (the function is not going to change :P).
  • We press the button.
  • The browser receives an event which will enter the angular context (I will explain why, later in this article).
  • The $digest loop will run and will ask every $watch for changes.
  • Since the $watch which was watching for changes in $scope.name reports a change, if will force another $digest loop.
  • The new loop reports nothing.
  • The browser gets the control back and it will update the DOM reflecting the new value of $scope.name
The important thing here (which is seen as a pain-point by many people) is that EVERY event that enters the angular context will run a $digest loop. That means that every time we write a letter in an input, the loop will run checking every $watch in this page.

Entering the angular context with $apply

What says which events enter the angular context and which ones do not? $apply
If you call $apply when an event is fired, it will go through the angular-context, but if you don’t call it, it will run outside it. It is as easy as that. So you may now ask… That last example does work and I haven’t called $apply, why? Angular will do it for you. So if you click on an element with ng-click, the event will be wrapped inside an $apply call. If you have an input with ng-model="foo" and you write an f, the event will be called like this: $apply("foo = 'f';"), in other words, wrapped in an $apply call.

When angular doesn’t use $apply for us

This is the common pain-point for newcomers to Angular. Why is my jQuery not updating my bindings? Because jQuery doesn’t call $apply and then the events never enter the angular context and then the $digest loop is never fired.
Let’s see an interesting example:
Imagine we have the following directive and controller:
File: app.js
app.directive('clickable', function() {

return {
  restrict: "E",
  scope: {
    foo: '=',
    bar: '='
  },
  template: '<ul style="background-color: lightblue"><li>{{foo}}</li><li>{{bar}}</li></ul>',
  link: function(scope, element, attrs) {
    element.bind('click', function() {
      scope.foo++;
      scope.bar++;
    });
  }
}

});

app.controller('MainCtrl', function($scope) {
  $scope.foo = 0;
  $scope.bar = 0;
});
It binds foo and bar from the controller to show them in a list, then every time we click on the element, both foo and bar values are incremented by one.
What will happen if we click on the element? Are we going to see the updates? The answer is no. No, because the click event is a common event that is not wrapped into an $apply call. So that means that we are going to lose our count? No.
What is happening is that the $scope is indeed changing but since that is not forcing a $digest loop, the $watch for foo and the one for bar are not running, so they are not aware of the changes. This also means that if we do something else that does run an $apply, then all the $watch we have will see that they have changed and then update the DOM as needed.

Try it


If we click on the directive (the blue zone) we won’t see any changes, but if we click on the button to update the string next to it, we suddenly see how many times we clicked on the directive. Just what I said, the clicks on the directive won’t trigger any $digest loop but when the button is clicked on, the ng-click will call $apply and it will run the $digest loop, so all the $watchwe have are going to be checked for changes, and that includes the one for foo and the one for bar.
Now you are thinking that this is not what you want, you want to update the bindings as soon as you click on the directive. That is easy, we just need to call $apply like this:
element.bind('click', function() {
  scope.foo++;
  scope.bar++;

  scope.$apply();
});
$apply is a function of our $scope (or scope inside a directive’s link function) so calling it will force a $digest loop (except if there is a loop in course, in that case it will throw an exception, which is a sign that we don’t need to call $apply there).

Try it


It works! But there is a better way for using $apply:
element.bind('click', function() {
  scope.$apply(function() {
    scope.foo++;
    scope.bar++;
  });
})
What’s the difference? The difference is that in the first version, we are updating the values outside the angular context so if that throws an error, Angular will never know. Obviously in this tiny toy example it won’t make much difference, but imagine that we have an alert box to show errors to our users and we have a 3rd party library that does a network call and it fails. If we don’t wrap it inside an $apply, Angular will never know about the failure and the alert box won’t be there.
So if you want to use a jQuery plugin, be sure you call $apply if you need to run a $digest loop to update your DOM.
Something I want to add is that some people “feel bad” having to call $apply because they think that they are doing something wrong. That is not true. It is just Angular that is not a magician and it doesn’t know when a 3rd party library wants to update the bindings.

Using $watch for our own stuff

You already know that every binding we set has its own $watch to update the DOM when is needed, but what if we want our own watches for our purposes? Easy.
Let’s see some examples:
File: app.js
app.controller('MainCtrl', function($scope) {
  $scope.name = "Angular";
  
  $scope.updated = -1;
  
  $scope.$watch('name', function() {
    $scope.updated++;
  });
});
File: index.html
<body ng-controller="MainCtrl">
  <input ng-model="name" />
  Name updated: {{updated}} times.
</body>
That is how we create a new $watch. The first parameter can be a string or a function. In this case it is just a string with the name of what we want to $watch, in this case, $scope.name (notice how we just need to use name). The second parameter is what is going to happen when $watchsays that our watched expression has changed. The first thing we have to know is that when the controller is executed and finds the $watch, it will immediately fire.

Try it


I initialized the $scope.updated to -1 because as I said, the $watch will run once when it is processed and it will put the $scope.updated to 0.
Example 2:
File: app.js
app.controller('MainCtrl', function($scope) {
  $scope.name = "Angular";
  
  $scope.updated = 0;
  
  $scope.$watch('name', function(newValue, oldValue) {
    if (newValue === oldValue) { return; } // AKA first run
    $scope.updated++;
  });
});
File: index.html
<body ng-controller="MainCtrl">
  <input ng-model="name" />
  Name updated: {{updated}} times.
</body>
The second parameter of $watch receives two parameters. The new value and the old value. We can use them to skip the first run that every $watch does. Normally you don’t need to skip the first run, but in the rare cases where you need it (like this one), this trick comes in handy.
Example 3:
File: app.js
app.controller('MainCtrl', function($scope) {
  $scope.user = { name: "Fox" };
  
  $scope.updated = 0;
  
  $scope.$watch('user', function(newValue, oldValue) {
    if (newValue === oldValue) { return; }
    $scope.updated++;
  });
});
File: index.html
<body ng-controller="MainCtrl">
  <input ng-model="user.name" />
  Name updated: {{updated}} times.
</body>
We want to $watch any changes in our $scope.user object. Same as before but using an object instead of a primitive.

Try it


Uhm? It doesn’t work. Why? Because the $watch by default compares the reference of the objects. In example 1 and 2, every time we modify $scope.name it will create a new primitive, so the $watch will fire because the reference of the object is new and that is our change. In this new case, since we are watching $scope.user and then we are changing $scope.user.name, the reference of $scope.user is never changing because we are creating a new $scope.user.nameevery time we change the input, but the $scope.user will be always the same.
That is obviously not the desired case in this example.
Example 4:
File: app.js
app.controller('MainCtrl', function($scope) {
  $scope.user = { name: "Fox" };
  
  $scope.updated = 0;
  
  $scope.$watch('user', function(newValue, oldValue) {
    if (newValue === oldValue) { return; }
    $scope.updated++;
  }, true);
});
File: index.html
<body ng-controller="MainCtrl">
  <input ng-model="user.name" />
  Name updated: {{updated}} times.
</body>

Try it


Now it is working! How? We added a third parameter to the $watch which is a bool to indicate that we want to compare the value of the objects instead of the reference. And since the value of $scope.user is changing when we update the $scope.user.name the $watch will fire appropriately.
There are more tips & tricks with $watch but these are the basics.

Conclusion

Well, I hope you have learnt how data-binding works in Angular. I guess that your first impression is that this dirty-checking is slow; well, that is not true. It is fast as lightning. But yes, if you have something like 2000-3000 $watch in a template, it will become laggy. But I think that if you reach that, it would be time to ask an UX expert :P.
Anyway, in a future version of Angular and with the release of EcmaScript 6, we will have Object.observe which will improve the $digest loop a lot. Meanwhile there are some tips & tricks that I am going to cover in a future article.