Magic Of Dependency Injection in Angular 2

Knoldus Inc.
Knoldus - Technical Insights
4 min readJun 15, 2017

When i was a kid Injection word was my biggest nightmare, but since I have become a programmer and jovial by doing clean, crisp and precise applications the “injection” word seems the most wonderful word to me, as this word brings so much ease, reduces so much coding effort and helps us to build a project quickly. When I took Angular 2 to build my application then as most people do, I also had a look into Angular 2’s documentation and there i find this definition of Dependency Injection :-

Dependency injection is an important application design pattern. Angular has its own dependency injection framework, and you really can’t build an Angular application without it. It’s used so widely that almost everyone just calls it DI

They have clearly mentioned that “you really can’t build an Angular application without it so we can say that DI is the heart of AngularJS.

Pain of Maintaining As well As Testing Code Without Dependency Injection

Let’s understand what DI really is. Consider the following code:

class College {
constructor() {
this.student = new Student();
this.professor = Professor.getInstance();
this.dean = app.get('dean');
}
}

In our class “College” we have a constructor which has some internal properties and i have tried to take all of them differently. The problem with this code is that it is not only hard to maintain, but also hard to test. For example, you can’t test the code separately without its dependencies or let’s say you want to replace its properties to something else (i.e., FirstName(), LastName(), etc.), then it’s not possible to do so with this approach.

But if we move the dependencies to the constructor, it will make a huge diffrence, So whenever someone wants to create the class, he/she needs to supply the dependencies as well. This is called dependency injection.

class College {
constructor(student, professor, principal) {
this.student = student;
this.professor = professor;
this.dean = dean;
}
}

This not only allows you to define classes without the need for initializing dependencies, but also enables you to use the same Instance of the dependencies in several classes.

Dependency Injection in Angular 2

Statements that look like @SomeName are decorators. Decorators are a proposed extension to JavaScript. In short, decorators let programmers modify and/or tag methods, classes, properties and parameters. There is a lot to decorators. In this blog the focus will be on decorators relevant to DI:@Inject and @Injectable.

@Inject() is a manual mechanism for letting Angular know that a parameter must be injected. It can be used like so

import {Component, Inject} from '@angular/core';
import {AppService} from "../app.service";
import {Task} from "../task";
import {Router} from "@angular/router";
@Component({
selector: 'show',
templateUrl: './app/showTask/showTask.component.html',
styleUrls: ['']
})
export class ShowComponent {
constructor(@Inject (AppService) private service) {
}
In the above we've asked forAppService to be the singleton Angular associates with the classsymbolAppService by calling @Inject(AppService). It's important to note that we're using AppService for its typings and as a reference to its singleton. We are not using AppService to instantiate anything, Angular does that for us behind the scenes.
@Injectable() lets Angular know that a class can be used with the dependency injector.@Injectable() is not strictly required if the class has other Angular decorators on it or does not have any dependencies. What is important is that any class that is going to be injected with Angular is decorated. However, best practice is to decorate injectables with @Injectable(), as it makes more sense to the reader.import {Injectable} from "@angular/core";
import {Task} from "./task";
@Injectable()
export class AppService {
taskArray: Task[] = [];
delete(index: number) {
this.taskArray.splice(index, 1);
}
add(task:Task){
if (this.taskArray.indexOf(task) == -1) {
this.taskArray.push(task);
}
}
update(index:number, task:Task){
if (this.taskArray.indexOf(task) == -1) {
this.taskArray[index] = task;
}
}
}
In the above example Angular's injector determines what to inject into AppService's constructor by using type information. This is possible because these particular dependencies are typed, and are not primitive types. In some cases Angular's DI needs more information than just types.
More About Dependency InjectionDependency injection in Angular2 relies on hierarchical injectors that are linked to the tree of components.This means that you can configure providers at different levels:
  • For the whole application when bootstrapping it. In this cases, all sub injectors (the component ones) will see this provider and share the instance associated with. When interacting, it will be the same instance
  • For a specific component and its sub components. Same as before but for à specific component. Other components won’t see this provider. If you redefine something defined above (when bootstrapping for example), this provider will be used instead. So you can override things.
  • For services. There are no providers associated with them. They use ones of the injector from the element that triggers (directly = a component or indirectly = a component that triggers the call of service chain)
To demonstrate more i have created a small example here is the link: GithubReferences:
Official Angular Documentation: here
Angular 2 Training Book: here
Thanks for reading, keep sharing.
knoldus-advt-sticker

--

--

Knoldus Inc.
Knoldus - Technical Insights

Group of smart Engineers with a Product mindset who partner with your business to drive competitive advantage | www.knoldus.com