Reader small image

You're reading from  Getting Started with Angular - Second edition - Second Edition

Product typeBook
Published inFeb 2017
Reading LevelIntermediate
PublisherPackt
ISBN-139781787125278
Edition2nd Edition
Languages
Tools
Right arrow
Author (1)
Minko Gechev
Minko Gechev
author image
Minko Gechev

Minko Gechev is a software engineer who strongly believes in open source software. He has developed numerous such projects including codelyzer, the AngularJS style guide, aspect.js and many others, and is one of the coauthors of the official Angular style guide.
Read more about Minko Gechev

Right arrow

Chapter 5. Dependency Injection in Angular

In this chapter, we'll explain how to take advantage of the dependency injection (DI) mechanism of the framework, with all its various features.

We will explore the following topics:

  • Configuring and creating injectors.

  • Instantiating objects using injectors.

  • Injecting dependencies into directives and components-this way, we will be able to reuse the business logic defined within the services and wire it up with the UI logic.

  • Annotating ES5 code in order to get the exact same result we get when we use the TypeScript syntax.

Why do I need DI?


Let's suppose that we have a Car class that depends on Engine and Transmission classes. How can we implement this system? Let's take a look:

class Engine {...} 

class Transmission {...}
 
class Car { 
  engine; 
  transmission;
 
  constructor() { 
    this.engine = new Engine(); 
    this.transmission = new Transmission(); 
  } 
} 

In the preceding example, we create the dependencies of the Car class inside its constructor. Although it looks simple, it is far from being flexible. Each time we create an instance of the Car class, in its constructor, instances of the same Engine and Transmission classes will be created. This may be problematic because of the following reasons:

  • The Car class gets less testable because we can't test it independently of its engine and transmission dependencies.

  • We couple the Car class with the logic used for the instantiation of its dependencies.

DI in Angular


Another way we can approach this is by taking advantage of the DI pattern. We're already familiar with it from AngularJS; let's demonstrate how we can refactor the preceding code using DI in the context of Angular:

class Engine {...} 
class Transmission {...} 
 
@Injectable() 
class Car { 
  engine; 
  transmission;
 
  constructor(engine: Engine, transmission: Transmission) { 
    this.engine = engine; 
    this.transmission = transmission; 
  } 
} 

All we did in the preceding snippet was add the @Injectable class decorator on top of the definition of the Car class and provide type annotations for the parameters of its constructor.

Benefits of DI

There is one more step left, which we'll take a look at in the next section. Before that, let's take a look at what the benefits of the mentioned approach are:

  • We can easily pass different versions of the dependencies of the Car class for a testing environment, or for instantiating...

Configuring an injector


The primitive used for the instantiation of the individual dependencies in our Angular applications via the DI mechanism of the framework is called the injector. The injector contains a set of providers that encapsulate the logic for the instantiation of registered dependencies associated with tokens. We can think of tokens as identifiers of the different providers registered within the injector.

Let's take a look at the following snippet, which is located at ch5/ts/injector-basics/injector.ts:

import 'reflect-metadata';
import {
  ReflectiveInjector,
  Inject,
  Injectable,
  OpaqueToken
} from '@angular/core';

const BUFFER_SIZE = new OpaqueToken('buffer-size');

class Buffer {
  constructor(@Inject(BUFFER_SIZE) private size: Number) {
    console.log(this.size);
  }
}

@Injectable()
class Socket {
  constructor(private buffer: Buffer) {}
}

let injector = ReflectiveInjector...

Defining factories for instantiating services


Now, let's suppose that we want to create a complex object, for example, one that represents a Transport Layer Security (TLS) connection. A few of the properties of such an object are a socket, a set of crypto protocols, and a certificate. In the context of this problem, the features of the DI mechanism of Angular we have looked at so far might seem a bit limited.

For example, we might need to configure some of the properties of the TLSConnection class without coupling the process of its instantiation with all the configuration details (choose appropriate crypto algorithms, open the TCP socket over which we will establish the secure connection, and so on).

In this case, we can take advantage of the useFactory property of the provider's configuration object:

let injector = ReflectiveInjector.resolveAndCreate([ 
  { 
    provide: TLSConnection, 
    useFactory: (socket: Socket, certificate: Certificate, crypto: Crypto) 
      ...

Child injectors and visibility


In this section, we will take a look at how we can build a hierarchy of injectors. This is a completely new concept in the framework introduced by Angular 2. Each injector can have either zero or one parent injectors, and each parent injector can have zero or more children. In contrast to AngularJS where all the registered providers are stored in a flat structure, in Angular 2 and later versions, they are stored in a tree. The flat structure is more limited; for instance, it doesn't support the namespacing of tokens; we cannot declare different providers for the same token, which might be required in some cases. So far, we have looked at an example of an injector that doesn't have any children or a parent. Now, let's build a hierarchy of injectors.

In order to gain a better understanding of this hierarchical structure of injectors, let's take a look at the following diagram:

Figure 1

Here, we see a tree where each node is an injector, and each of these injectors...

Summary


In this chapter, we covered the DI mechanism of Angular. We briefly discussed the positives of using DI in our projects by introducing it in the context of the framework. The second step in our journey was how to instantiate and configure injectors; we also explained the injectors' hierarchy and the visibility of the registered providers. In order to enforce a better separation of concerns, we mentioned how we can inject services carrying the business logic of our application in our directives and components. The last point we took a look at was how we can use the DI mechanism with the ES5 syntax.

In the next chapter, we'll introduce the new routing mechanism of the framework. We'll explain how we can configure the component-based router and add multiple views to our application. Another important topic we will cover is the new form module. By building a simple application, we will demonstrate how we can create and manage forms.

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Getting Started with Angular - Second edition - Second Edition
Published in: Feb 2017Publisher: PacktISBN-13: 9781787125278
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Minko Gechev

Minko Gechev is a software engineer who strongly believes in open source software. He has developed numerous such projects including codelyzer, the AngularJS style guide, aspect.js and many others, and is one of the coauthors of the official Angular style guide.
Read more about Minko Gechev