Check out our Angular Book Series.

Creating an Angular Service - Dependency Injection and Angular - Part 1

I was chatting with a colleague recently, and he had some confusion about how dependency injection works with Angular. There are a bunch of ways to set up Dependency Injection with Angular, but as always the documentation seems lacking. I'm writing this series of posts to discuss the ways and to explain what works and what won't work.

This post will explain what Dependency Injection is, create a basic Angular application, and generate a default service.

What is Dependency Injection?

First I want to explain what Dependency Inection is. Dependency Injection is a fancy way to say you're automatically passing one class access to another. The dependency is called a service, while the receiving object is called the client. The process of creating the service is done outside the client, so the client does not need any knowledge of how to create its dependencies, it can just use it. This allows for greater encapsulation and reuse.

Often a framework can be used to create the dependency and inject it into client. Angular has Dependency Injection built right in and that's what I'm going to talk about today.

The Setup

I created a brand new project using the Angular CLI:


ng new InjectionExperiments

You should see the console chug for a bit:

This will create a new Angular application that we'll use as our base. I'm going to create a few components too:


ng generate component view1

And then


ng generate component view2

You'll see something like this:

I'm going to change the main display, app.component.html to include the two new components:


<app-view1></app-view1>
<br/>
<app-view2></app-view2>

Now you can run the app:

Load it in the browser:

If you've done any Angular development before, these are probably steps you've taken on.

Create a default Service

Now let's create a simple service which can be used to share data between the two components.


ng generate service services/service1

You'll see something like this:

We're ignoring the spec file for the purposes of these articles. Look at the service code:


import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class Service1Service {
constructor() { }
}

This is a standard TypeScript class, with one important distinction. It has an Angular decorator, Injectable, placed into it. This is the metadata that tells Angular to set this class up as a service. It also accepts an object config with the providedIn value. This value tells Angular to inject this service into the root module. Doing so will make this service available to all components in the application.

A service in Angular is a singleton. A single instance of the service class is created, and the same instance will be injected everywhere. This is what makes dependency injection so powerful. The same functionality and data can be shared among many different components, pipes, directives, and even other services.

Let's add a value into the service:


myValue = 'default';

To demonstrate how services work, we're going to share this value between both view1 and view2 and show that edits in view1 will automatically show up in view2.

Before we start on that, load the FormsModule into the main application. Open up app.module.ts and find the import section of the NgModule metadata. Add FormsModule:


imports: [
BrowserModule,
FormsModule
],

Be sure to import the FormsModule:


import {FormsModule} from '@angular/forms';

Now, let's open up the view1.component.ts. Find the constructor and modify it to look like this:


constructor(public service1: Service1Service) { }

You'll need to import the service here:


import {Service1Service} from '../services/service1.service';

This is the Angular dependency injection syntax at play. The variables in the constructor tell Angular to look for an instance of Service1Service and inject it into this component when it is created.

Open up view1.component.html and replace all the contents with this:


<h1>View 1</h1>
<input [(ngModel)]="service1.myValue">

We are using the ngModel directive with two way binding. When service1's myValue changes the input text will be updated. When the input changes, service1's myValue will update.

Now go to view2.component.ts ad inject service1 into the constructor using the same syntax that we used to inject it into view1:


constructor(public service1: Service1Service) { }

And you'll need to input the value here:


import {Service1Service} from '../services/service1.service';

Open view2.component.html and replace all its contents with this:


<h1>View 2</h1>
{{service1.myValue}}

Here we are just using Angular notation to evaluate the expression, in this case it just returns service1.myValue.

Now rerun the app and load it in the browser. You should see something like this:

Type in the input box from the view1 component and you'll see the output display in the view2 component.

Congratulations, you made your first service. By default, all your services are injected into the root module, but sometimes you don't need a global service, you just need a service for a specific section of the site, or maybe a single screen.

What's Next

You can play with the code here.

In the next article of this series, I'm going make some changes to the Injectable() metadata on the service, and see how that affects things.

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
Comments are not allowed for this entry.
All Content Copyright 2005, 2006, 2007, 2008, 2009 Jeffry Houser. May not be reused without permission
BlogCFC was created by Raymond Camden. This blog is running version 5.9.2.002.