UPDATE (8th May 2016): This tutorial has been updated to the latest version of Angular (Angular 4). Note that the Angular team has re-branded the terms
Angular 2 to
Angular 1.x to
AngularJS which are now the official names of these frameworks.
This is the second article on the Getting Started with Angular 2 Step by Step series if you missed the first article go and check it out!
Ok! So you’ve learned how get started with an Angular 2 and TypeScript application and you’ve written your first component. Yey! The next thing you are going to learn about are services and dependency injection.
In the previous example we had a
PeopleListComponent where we initialized an array of Star Wars persons of note. But your component shouldn’t know or care about where the list of people is coming from be it local storage, a database, a web service or the grace of the holy spirit.
That’s why we are going to extract that data access logic into a service that we’ll inject into our component through its constructor. Breaking your application in smaller pieces that have a single responsiblity will make it much easier to reason about, more maintainable, reusable and testable. Win Win!
The Code Samples
You can download the code samples for this article from this GitHub repository.
Our People List Component Right Now
So this is how our
PeopleListComponent looks right now:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
Our mission is to extract the data access logic into a separate
PeopleService service that will encapsulate that responsibility of retrieving people from wherever people come from and provide that as a service for the rest of the application.
I know, our current data access logic is super simple, we are just instantiating an array and that’s it, but in the very near future we will be using a service, so bear with me :).
What is an Angular 2 Service?
Every application is composed of a lot of subsystems that do different things like logging, data access, caching, specific application domain knowledge, etc. Depending on the type of application that you are building or the framework that you are using there’s different ways to represent these subsystems.
Angular 2 uses the concept of services, an Angular service is a class that encapsulates some sort of functionality and provides it as a service for the rest of your application.
If you have an AngularJS background you’ll welcome this simplification in the Angular conceptual model: there’s no more service/factory/constant/provider conumdrum. In Angular 2 there’s only services, and they are just vanilla ES6 classes.
Creating The PeopleService
Let’s create our new
PeopleService in a new file
people.service.ts. We’ll take advantage of the Angular cli generators and run the following command:
1 2 3
This will create an empty service called
people.service.ts that will look like this:
1 2 3 4 5 6 7 8
Now if we extract the data access code from our
PeopleListComponent into the service we’ll get the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
As you can see above this is just a vanilla ES6 class that exposes a
getAll method which returns a list of persons.
Injecting Our People Service in The People List Component
Now that we have a service that encapsulates Star Wars person data access we can use it from our
PeopleListComponent. We will take advantage of dependency injection and inject the service through the component’s constructor.
Real world applications do a lot of things.
In order to manage this innate complexity of real world systems we break them down into smaller subsystems that ideally do one thing or a teeny tiny set of things.
As a result of that we have a simpler system made up of small components that depend on each other. Initially we may have these as hard-set dependencies (for instance using the new operator to instantiate them), but we want these dependencies to know the least amount of information possible about each other. We want each subsystem to depend on abstractions and not concrete implementations.
Why? Because that way we can create systems that are more flexible, extensible and sturdy where changes in concrete implementations don’t propagate to other parts of the system.
So we have these nice collection of subsystems that depend only of abstractions. But… how are we supposed to work with them and create a real program out of them? or, what is the same, how can we make them use the real dependencies at runtime? Well, that’s where dependency injections comes in. It’s the mechanism by which we can introduce real implementations to these subsystems that can do real work at runtime.
Using Angular 2 Dependency Injection to Inject Our People Service in the People List Component
We start by importing the
PeopleService from the
Using Visual Studio Code? Add imports automatically with quick fixes
Are you using Visual Studio Code for your Angular 2 Coding? In that case you may like this nifty trick that automatically adds imports to your TS file.
If you type PeopleService without the import statement the VS code editor will prompt you through a quick fix (a lightbulb on the left side of the editor) to automatically import the statement. You can trigger the quick fix menu using the keyboard using the
. key in your Mac or
. key in your PC.
Then we inject it into the
PeopleListComponent via its constructor:
1 2 3 4 5 6 7 8 9
TypeScript Private Class Members Are Awesome
This is a feature that hasn’t yet arrived to ES6 classes. You can simulate data privacy with Symbols and closures but it becomes very wordy and uncomfortable.
TypeScript makes declaring private class members a breeze.
We use the TypeScript shorthand syntax to directly declare a private member of the
private peopleService in the constructor is equivalent to:
1 2 3 4 5 6 7 8 9
And we’re done, the whole
PeopleListComponent now looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
If you had your http server running (if you don’t run
ng serve) you’ll see how… it didn’t work!!
Hmm… everything looks fine…
PeopleService… open your browser dev tools and you’ll discover the following error message:
Aha! Angular 2 doesn’t know how to inject a
PeopleListComponent. Let’s see how to do that next.
Registering Your Service With Angular 2
In order to register a service with Angular 2 you use the
providers property within the
Component decorator. For instance, to make the
PeopleService available throughout our app we can register it within the
AppComponent component. This will make it available to this component and all its children (like
PeopleListComponent). We start by importing the service from its module:
And adding it to the
providers property within the
1 2 3 4 5 6 7 8 9 10 11 12
In some way we can compare this
providers property to the configuration section of an IoC (inversion of control) container.
In this particular example we are cheating a little bit because we are using concrete classes both in the
PeopleListComponent constructor and in this
providers property. Bear with me, I’ll try to keep it as simple as possible in these first articles in the series and I’ll expand on dependency injection in Angular 2 later on.
Ok, ok… hehe if you can’t wait, you can make your application depend on abstractions right away using this more verbose approach:
1 2 3 4 5 6 7 8 9
You Can Also Register Services at the Module Level
NgModule decorator after RC5 and the new concept of Angular 2 Modules you can now register services to be used throughout a whole module. You can achieve that via the
providers property of the
1 2 3 4 5 6 7 8 9
When would you want to do that? – you may wonder. Well, whenever you want to use the same instance of a service for your whole application.
The Angular Cli Can Help You With Registering! Yey!
The Angular Cli can also help you register your services. When you generate a new service there is one additional flag that you can use to inject the registering code inside a module in addition to generating the new service: the
--module flag (
-m in short-hand).
For instance, the following example would have generated the
PeopleModule and registered it inside our
1 2 3
Cool right? The Angular cli strikes back and saves us some additional keystrokes.
Taking Advantage of Angular 2 Component Lifecycle
Another Angular 2 improvement over AngularJS is that now it is dead easy to hook into the component lifecycle. For instance, we can make our constructor much leaner and move the data initialization to the
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
This is going to be helpful when writing unit tests because we can count on the fact that the component won’t do any heavy lifting when we instantiate it. Additionally, a component inputs aren’t yet available within a class constructor but only later on in the
OnInit lifecycle hook (You’ll learn about inputs later in the series).
Enabling Dependency Injection in Your Service
We saw how to inject stuff in a component, but how do you inject stuff in a service? Well you follow the same process that you do with components by injecting the dependency in the constructor and registering in the
providers property of the root component. And additionally you need to decorate the service with the
Injectable decorator just as you can see in the example below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Why don’t we use the
Injectable decorator in components? We’ll that’s because the
Component decorator enables dependency injection directly.
Whenever you use the Angular cli to generate your services it will add the
Injectable decorator for you. So use the Angular cli and you can forget this section altogether and live happily ever after.
Want to Know More About Angular 2 Dependency Injection?
Would you like to learn more about Angular 2 dependency injection and you cannot wait till I write a following article about it? Worry not, check these two great articles:
- Dependency Injection in AngularJS and Angular by Viktor Savkin one of the core Angular 2 core team members
- Dependency Injection in Angular 2 from the Thoughtram blog
- Dependency Injection in Angular 2 from the Angular 2 docs
Well done! Now you know both about components, services and dependency injection. Up next we are going to learn more about Angular 2 data binding by creating a second component that will help us discover more information about these Star Wars heroes of yore.
Have a great day!