Dependency injection in Angular with ES6

Most of Angular dependency injection examples come with Typescript, which is nice, but how can we do it in Javascript? ES5 is getting old and it’s examples are a bit too verbose, but in ES6 we can write it as readable as in Typescript!

If you don’t know how dependency injection works in Angular there is a very nice article on the Thoughtram blog.

First we need a service what will be injected into our component.

class CityService {
getCities() {
return ['London', 'Berlin', 'New York'];
}
}

Next we need to add the CityService as a provider to the application, what we can do at bootstrap.

bootstrap(AppComponent, [CityService]);

From now on we can use the CityService in components with a simple static getter, named parameters.

@Component({
selector: 'app',
template: `
<ul>
<li *ngFor="#city of getCities()">{{ city }}</li>
</ul>
`
})
class AppComponent {
static get parameters() {
return [[CityService]];
}

constructor(cityService) {
this._cityService = cityService;
}

getCities() {
return this._cityService.getCities();
}
}

You might wonder why is it wrapped inside two arrays. The answer is to be able to add more information about the injection, for example to mark it as optional.

import { Component, OptionalMetadata } from 'angular2/core';

static get parameters() {
return [[new OptionalMetadata(), CityService]];
}

It would look like this in Typescript inside the constructor.

constructor(private @Optional() cityService: CityService) {}

Technically it does the same, it just puts the dependency definition inside the constructor parameters instead of a static getter.

It’s fine we wrote it in ES6, but how to make it run in the browser? We need to transpile it. For this we can use Babel. It will transpile all the ES6 code into ES5 equivalents. Assuming the newest version of Babel (version 6), we need the es2015 preset to get it working. Besides ES6 features decorators nedd another plugin to work again with Babel 6, which is decorators-legacy plugin. The corresponding part of the .babelrc file looks like this.

{
"presets": ["es2015"],
"plugins": ["transform-decorators-legacy"]
}

So far this solution is strictly standards compliant. For a less strict way, but closer to Typescript, can be to use angular2-annotations plugin along with flow-strip-types plugin. With it the constructor can be written like this.

constructor(cityService: CityService) {
this._cityService = cityService;
}

The only disadvantage of this you can’t add any additional information to it like making the dependency optional. Just add the plugins to our .babelrc config.

{
"presets": ["es2015"],
"plugins": [
"angular2-annotations",
"transform-decorators-legacy",
"transform-flow-strip-types"
]
}

Wrapping up

Either way you go with the strict standards complaint or the more closer to Typescript way, now you can easily implement dependency injection in ES6.

For a complete application and more examples on it check out my starter CRUD application.


Thanks for reading! If you liked this story, please recommend it by clicking the ❤ button on the side and sharing it on social media. Follow me on Medium or Twitter to read more about Angular!

Show your support

Clapping shows how much you appreciated Gábor Soós’s story.