Forward Advance Learning

Services and Dependency Injection (DI)

We should now be used to writing controllers like this:

angular.module('app', [])
.controller('demoController', function($scope) {
$scope.name = 'Davey McGee';
}

You may not have realised that you can pass anything to your controller. Angular will intuit the type of thing that you want to pass in, and will take care of creating it for you.

We call this Dependency Injection or DI.

Here we have a controller that is receiving a $scope object and a $log object. Notice that we don't have to create the $scope and the $log. Angular just does this for us.

angular.module('app', [])
.controller('demoController', function($scope, $log) {
$scope.name = 'Davey McGee';
$log.log('Hi Davey!');
}

This is dark magic. JavaScript technically does not have this feature. Angular is actually making this work by converting the function declaration into a string, then using a regex to parse out the method signature.

Exercise - Try some DI

Have a go at this. Pass a $log object into one of your controllers and verify that this works.

Reverse the order of imports, pass in the $log first, then the $scope and verify that this does indeed work.

Services, Factories and Values

Angular comes with many built in injectables, but the fun starts when we start to define our own.

Services and Factories are objects Angular injectables that we use to create objects. They are very similar to one another and are often used interchangeably.

  • Service and factories both yield singleton objects.
  • Once created this object will persist and you will get the same object back each time you request it.
  • We can inject services and factories into controllers using DI.

A Service

We compose a service by giving Angular a newable function (one which writes to "this").

angular.module('app')
.service('helloService', function() {
this.sayHello = function() {
alert("Hello");
};
});

A Factory

A factory on the other hand composes an object and returns it:

angular.module('app')
.factory('helloFactory', function() {
return {
sayHello: function() {
alert("Hello");
}
};
});

Making use of factories and services

Once we declare them, services and factories become injectable. Let's inject them into a controller:

angular.module('app')
.controller('myController', function(helloService, helloFactory) {
helloService.sayHello();
helloFactory.sayHello();
})

Exercise - A service for the repeat and filter

In an earlier exercise, we created an app that created a list of henchmen, and used ng-repeat to list them.

We put the list of henchmen right into $scope from inside our controller. I said at the time that this was not such a great thing to do.

In this exercise we are going to rectify this situation with a service or a factory.

  1. Create a factory that contains a method that will return a list of henchmen.
  2. Inject this into your controller.
  3. Now call the method on the factory from inside your controller, and save the resulting object in $scope.

For bonus points, recode the factory as a service.

Further Exercise - Simple shopping cart service

  1. Create a service to manage a shopping cart. Give it a cart variable which holds an array of objects.
  2. Add an addToCart function to the service which pushes an item into the cart.
  3. Write a controller to display the cart. Inject the cart into your controller.
  4. In your controller, write a simple method on $scope which calls shoppingCart.addToCart.
  5. In your controller, create an attribute of $scope that holds the shoppingCart.cart.
  6. Write a view to render the cart.

Exercise - NgDialog

We are going to inject the ngDialog service into a controller. This will allow our controller to create popup dialog boxes.

First go here and grab the ng-dialog.js. Link it in the header of your document in the usual way with a script tag.

Now download the CSS files: ng-dialog.css and ng-dialog-theme-plain.css. Link them using link tags.

http://ngmodules.org/modules/ngDialog

Include it in your app.

We need to include ngDialog as a dependency of the app, like this:

angular.module('app', ['ngDialog'])

Inject into your controller.

Create a little controller and use the ng-controller directive to hook it to the DOM.

<div ng-controller="myController">

Inject the ngDialog service into your controller.

.controller('myController', function($scope, ngDialog) {
})

You now have access to ngDialog.open. Call this according to the documentation to create a dialog box when the page loads: https://github.com/likeastore/ngDialog#api

e.g.

ngDialog.open({
template: '<p>my template</p>',
className: 'ngdialog-theme-plain',
plain: true
});