This blog post is a brief introduction to one of the core concepts of Angular – Services and Dependency Injection. A service is basically a typescript class. It acts as a central repository where we can store and centralize our code and data. This service class can then be shared across components. Dependency injection is a mechanism that injects an instance of the service class into a component.
Why do we need services?
Let’s assume we have an app with two components: ‘new-hero’ and ‘heroes,’ along with the app component. The component ‘new-hero’ allows us to create a hero and add it to an array. The component ‘heroes’ lists all the heroes from that array.
We can now make use of a service that has a class containing a ‘heroes’ array and its associated methods. These methods can be to add and remove items from the ‘heroes’ array.
<div class="container"> <div class="row"> <div class="col-xs-12 col-md-8 col-md-offset-2"> <app-new-hero></app-new-hero> <hr> <app-heroes *ngFor="let hero of heroes; let i = index" [hero]="hero" [id]="i"></app-heroes> </div> </div> </div>
app-component.html that has two components, ‘new-hero’ and ‘heroes’
How do you create a service?
For our example, we need a heroes service and we create a file called heroes.service.ts in the app folder. This file now contains a HeroesService class with a heroes array and two methods: ‘createHero’ and ‘removeHero.’ They do the job of adding and removing items from the array, respectively.
export class HeroesService { heroes = [ { name: 'Captain America', universe: 'Marvel' }, { name: 'Iron Man', universe: 'Marvel' }, { name: 'Wonder Woman', universe: 'DC' }, { name: 'Flash', universe: 'DC' } ] createHero(name: string, universe: string) { this.heroes.push({name: name, universe: universe}); } removeHero(id:number) { this.heroes.splice(id, 1); } }
We now need to import our service into app.module.ts and add it as part of the ‘Providers’ so that it is accessible by all the components.
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { NewHeroComponent } from './new-hero/new-hero.component'; import { HeroesService } from './heroes.service'; import { HeroesComponent } from './heroes/heroes.component'; @NgModule({ imports: [ BrowserModule, FormsModule ], declarations: [ AppComponent, NewHeroComponent, HeroesComponent ], bootstrap: [ AppComponent ], providers: [ HeroesService ] }) export class AppModule { }
Injecting Services into a Component
Import the HeroService in to the component. Instruct Angular to inject a dependency in the component’s constructor by specifying a parameter with the dependency type. We now have an injected ‘HeroesService’ in our component and can use it to access the array and methods in that service. This means we have an instance of ‘HeroesService’ class in our component as ‘heroesService.’ We then instantiate the ‘heroes’ array by making use of ‘heroesService.’
import { Component, OnInit } from '@angular/core'; import {HeroesService} from './heroes.service'; @Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: [ './app.component.css' ] }) export class AppComponent implements OnInit { //create heroes array heroes: {name: string, universe: string}[] = []; //inject HeroesService as a constructor parameter constructor(private heroesService: HeroesService) {} ngOnInit() { //Instantiate heroes array with the HeroesService heroes array this.heroes = this.heroesService.heroes; } }
Accessing Service in a Component
The ’new-hero’ component takes two input parameters – hero name and hero universe. It also has a click event that calls a function onCreateHero() with these two input parameters as arguments.
<div class="row"> <div class="col-xs-12 col-md-8 col-md-offset-2"> <h2>Create a Hero</h2> <div class="form-group"> <label>Hero Name</label> <input type="text" class="form-control" #heroName> </div> <div class="form-group"> <select class="form-control" #universe> <option value="Marvel">Marvel</option> <option value="DC">DC</option> </select> </div> <button class="btn btn-primary" (click)="onCreateHero(heroName.value, universe.value)"> Create Hero </button> </div> </div>
The new-hero.component.ts imports HeroesService and injects it through a constructor and has an instance of this class. The ‘onCreateHero’ function can now access the method ‘createHero’ off the newly instantiated heroesService class. We then add items to the ‘heroes’ array.
import { Component, OnInit } from '@angular/core'; import { HeroesService } from '../heroes.service'; @Component({ selector: 'app-new-hero', templateUrl: './new-hero.component.html', styleUrls: ['./new-hero.component.css'] }) export class NewHeroComponent implements OnInit { constructor(private heroesService: HeroesService) { } onCreateHero(heroName: string, heroUniverse: string) { this.heroesService.createHero(heroName, heroUniverse); } ngOnInit() { } }
Similarly, the heroes component can now access the method ‘removeHero’ of heroesService class to remove items from the ‘heroes’ array.
import { Component, OnInit, Input } from '@angular/core'; import {HeroesService} from '../heroes.service'; @Component({ selector: 'app-heroes', templateUrl: './heroes.component.html', styleUrls: ['./heroes.component.css'] }) export class HeroesComponent implements OnInit { @Input() hero: {name: string, universe: string}; @Input() id: number; constructor(private heroesService: HeroesService) { } ngOnInit() { } removeHero() { this.heroesService.removeHero(this.id); } }
This is a brief introduction to one of the core concepts of Angular – Services and Dependency Injection. A complete working example of this app can be found here: https://stackblitz.com/edit/angular-services-dependencyinjection