Angular2: Dependency Injection


In the last article, we’ve explored basic differences between Angular 1 and 2 with respect to Component over Directive, TypeScript over ES5, ES6 Class over Controller, and Decorators/Annotations. We’ve pretty much got acquainted with setting up Angular2 in TypeScript with SystemJS to begin our journey with Angular2 in coming weeks. In this article, we’ll investigate how dependency injection that we always loved is different in Angular2 than Angular1. We are not going to cover what dependency injection is in this article though, so if you are not familiar with it yet, follow the documentation for more information.

Angular1

As usual, we’ll quickly go through the Angular1 example. Let’s take a simple example (HTML and JS) from my free ebook on Angular1 Directives that explores how DI works in Angular1. Notice we’ve used ngController directive in which we are going to inject a custom service. Also stare at ngApp directive which was a recommended way to bootstrap an application automatically in Angular1 rather than manually using angular.bootstrap method.

<html ng-app="DI">
<head>
  <title>AngularJS: DI</title>
  <script src="../bower_components/angular/angular.js"></script>
  <script src="../js/ch01/di.js"></script>
</head>
<body ng-controller="SayHi">

<h1>Check the console</h1>

</body>
</html>

Here is the JavaScript code for the above example. We have defined the custom service named Hello and later injected the same into the controller called SayHi.

var App = angular.module('DI', []);
App.service('Hello', function() {
  var self = this;
  self.greet = function(who) { 
    self.name = 'Hello ' + who;
  }
});

App.controller('SayHi', function(Hello) {
  Hello.greet('AngularJS');
  console.log(Hello.name);
});

Now that we’ve our demo up and running, it’s time to migrate it to Angular2.

Angular2

Let us first update the JS code first and walk through the changes.

import { NgModule, Component, Injectable } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

@Injectable()
class HelloService {
  name: string;
  
  greet(who) {
    this.name = 'Hello ' + who;  
  }  
}

@Component({
  selector: 'ng-app',
  template: '<h1>Check the console</h1>'
})
export class DIComponent {
  constructor(public Hello: HelloService) {
    this.Hello.greet('Angular2');
    console.log(this.Hello.name);
  }
}

@NgModule({
  declarations: [DIComponent],
  imports:      [BrowserModule],
  providers:    [HelloService],
  bootstrap:    [DIComponent]
})
export default class MyAppModule {}

platformBrowserDynamic().bootstrapModule(MyAppModule);

We are already familiar with Component, ES6 Class, bootstrap, etc. jargons from the previous article as these are the backbone of Angular2. The only difference here is the service, HelloService. However, if you notice, the service is itself a ES6 Class similar to our application component, DI. Just like @Component annotation is there to tell Angular2 to treat a ES6 class as a component, the @Injectable annotation annotated the ES6 Class as an Angular2 Service that is injected elsewhere.

In the above example, we’ve injected the service via providers options in the @NgModule. This way the instance of the service will be available for the entire component only and its child components, if any. However, services in Angular2 are not singleton by nature unlike Angular1 which means if the same service is injected as a provider in a child component, a new instance of the service will be created. This is a confusing thing for beginners so watch out.

The public Hello: HelloService parameter in the constructor is equivalent to Hello: HelloService = new HelloService();. It means Hello is an instance of HelloService and of a type HelloService (optional). One benefit of annotations/decorators in Angular2 in my opinion is that there is no confusion over Factory vs Service vs Provider, instead it’s just a ES6 class.

Slight changes compared to the previous example is that we need to give more configurations in SystemJS for typescript compilers to emit decorator MetaData so that generated ES5 code will work fine in a browser.

{
  "compilerOptions": {
    "target": "ES5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  }
}

Remember experimentalDecorators flag enables experimental support for ES7 decorators in TypeScript and emitDecoratorMetadata flag emits design-type metadata for decorated declaration in ES5 output, especially, for public Hello: HelloService code in the constructor as we’d seen before. Using the alternative mentioned above will not need these flags though.

Now let us update HTML markup.

<html>
<head>
  <title>Angular2: DI</title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <!-- 1. Load libraries -->
  <script src="../node_modules/core-js/client/shim.min.js"></script>
  <script src="../node_modules/zone.js/dist/zone.js"></script>
  <script src="../node_modules/reflect-metadata/Reflect.js"></script>
  <script src="../node_modules/systemjs/dist/system.src.js"></script>

  <!-- 2. Configure SystemJS -->
  <script src="../systemjs.config.js"></script>
  <script>
    System.import('ch01/di').catch(function(err){ console.error(err); });
  </script>
</head>
<body>
  <!-- 3. Display the application -->
  <ng-app>Loading...</ng-app>
</body>
</html>

Wrap up

That’s it guys..! Wolksoftware‘s blog has covered a great intro to reflection in Typescript, if interested. In the next post, we’ll explore two-way databinding in Angular2, but meanwhile Checkout Dependency Injection in action.

Advertisements

3 thoughts on “Angular2: Dependency Injection

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s