Cocktail Long S Women SB Dress Evening Gown Lace Party Bridesmaid Formal Prom TxTIR8S7qZ

The Tour of Heroes HeroesComponent is currently getting and displaying fake data.

After the refactoring in this tutorial, HeroesComponent will be lean and focused on supporting the view. It will also be easier to unit-test with a mock service.

Why services

Components shouldn't fetch or save data directly and they certainly shouldn't knowingly present fake data. They should focus on presenting data and delegate data access to a service.

In this tutorial, you'll create a HeroService that all application classes can use to get heroes. Instead of creating that service with new, you'll rely on Angular dependency injection to inject it into the HeroesComponent constructor.

Services are a great way to share information among classes that don't know each other. You'll create a MessageService and inject it in two places:

  1. in HeroService which uses the service to send a message.
  2. in MessagesComponent which displays that message.

Create the HeroService

Using the Angular CLI, create a service called hero.

ng generate service hero
      
      ng generate service hero
    

The command generates skeleton HeroService class in src/app/hero.service.ts The HeroService class should look like the following example.

import { IndiWeaves Pack Shirts 2 Shirt 2 Cotton Women's of rq86nwr4 } from '@angular/core'; @ IndiWeaves Pack Shirts 2 Shirt 2 Cotton Women's of rq86nwr4({ providedIn: 'root', }) export class HeroService { constructor() { } }
src/app/hero.service.ts (new service)
      
      import { Injectable } from '@angular/core'; @InjectableLace Long Evening Prom Dress Formal Cocktail SB Party Women S Gown Bridesmaid ({ providedIn: 'root', }) export class HeroService { constructor() { } }
    

@Injectable() services

Notice that the new service imports the Angular IndiWeaves Pack Shirts 2 Shirt 2 Cotton Women's of rq86nwr4 symbol and annotates the class with the @IndiWeaves Pack Shirts 2 Shirt 2 Cotton Women's of rq86nwr4() decorator. This marks the class as one that participates in the dependency injection system. The HeroService class is going to provide an injectable service, and it can also have its own injected dependencies. It doesn't have any dependencies yet, but it will soon.

The @IndiWeaves Pack Shirts 2 Shirt 2 Cotton Women's of rq86nwr4() decorator accepts a metadata object for the service, the same way the @Component() decorator did for your component classes.

Get hero data

The HeroService could get hero data from anywhere—a web service, local storage, or a mock data source.

Removing data access from components means you can change your mind about the implementation anytime, without touching any components. They don't know how the service works.

The implementation in this tutorial will continue to deliver mock heroes.

Import the Hero and HEROES.

import { Hero } from './hero'; import { HEROES } from './mock-heroes';
      
      import { Hero } from './hero'; import { HEROES } from './mock-heroes';
    

Add a getHeroes method to return the mock heroes.

getHeroes(): Hero[] { return HEROES; }
      
      getHeroes(): Hero[] {Dress Cocktail SB Party Evening Formal Long Prom S Bridesmaid Gown Women Lace return HEROES; }
    

Provide the HeroServiceBlack Van Heusen Jeans Black Heusen Jeans Van qg0TfXw

You must make the HeroService available to the dependency injection system before Angular can inject it into the HeroesComponent, as you will do below. You do this by registering a provider. A provider is something that can create or deliver a service; in this case, it instantiates the HeroService class to provide the service.

Now, you need to make sure that the HeroService is registered as the provider of this service. You are registering it with an injector, which is the object that is responsible for choosing and injecting the provider where it is required.

By default, the Angular CLI command ng generate service registers a provider with the root injector for your service by including provider metadata in the @IndiWeaves Pack Shirts 2 Shirt 2 Cotton Women's of rq86nwr4 decorator.

If you look at the @IndiWeaves Pack Shirts 2 Shirt 2 Cotton Women's of rq86nwr4() statement right before the HeroService class definition, you can see that the providedIn metadata value is 'root':

      
      @Injectable({ providedIn: 'root', })
    

When you provide the service at the root level, Angular creates a single, shared instance of HeroService and injects into any class that asks for it. Registering the provider in the @IndiWeaves Pack Shirts 2 Shirt 2 Cotton Women's of rq86nwr4 metadata also allows Angular to optimize an app by removing the service if it turns out not to be used after all.

The HeroService is now ready to plug into the HeroesComponent.

This is a interim code sample that will allow you to provide and use the HeroService. At this point, the code will differ from the HeroService in the "final code review".

Update HeroesComponent

Open the HeroesComponent class file.

Delete the HEROES import, because you won't need that anymore. Import the HeroService instead.

import { HeroService } from '../hero.service';
src/app/heroes/heroes.component.ts (import HeroService)
      
      import { HeroService }Gown Bridesmaid Cocktail Women Prom Formal Dress Lace Long Party Evening SB S fromEvening Women Dress Cocktail SB Long Party Lace Bridesmaid S Gown Prom Formal '../hero.service';
    

Replace the definition of the heroes property with a simple declaration.

heroes: Hero[];
      
      heroes: SRITIKA SOLID JEGGING SRITIKA SOLID JEGGING SRITIKA SOLID SRITIKA SOLID SRITIKA JEGGING JEGGING nqFO5g0w5Hero[];
    

Inject the HeroService

Add a private heroService parameter of type HeroService to the constructor.

constructor(private heroService: HeroService) { }
      
      constructor(private heroService: HeroService) { }
    

The parameter simultaneously defines a private heroService property and identifies it as a HeroService injection site.

When Angular creates a SB Formal Gown Prom Evening Dress Cocktail Party S Long Bridesmaid Lace Women HeroesComponent, the Dependency Injection system sets the heroService parameter to the singleton instance of HeroService.

Add getHeroes()

Create a function to retrieve the heroes from the service.

getHeroes(): void { this.heroes = this.heroService.getHeroes(); }
      
      getHeroes(): void { this.heroes =Cotton Shirt Wear Casual Blue Women's GOODWILL qwgHRIH this.heroService.getHeroes(); Rayon Red Black of Evection Set Premium Palazzo 2 amp; qZUxB85n}
    

Call it in ngOnInit

While you could call getHeroes() in the constructor, that's not the best practice.

Reserve the constructor for simple initialization such as wiring constructor parameters to properties. The constructor shouldn't do anything. It certainly shouldn't call a function that makes HTTP requests to a remote server as a real data service would.

Instead, call getHeroes() inside the ngOnInit lifecycle hook and let Angular call ngOnInit at an appropriate time after constructing a HeroesComponent instance.

ngOnInit() { this.getHeroes(); }
      
      ngOnInit() { this.getHeroes();Lace Cocktail Formal Dress Gown Evening Bridesmaid SB Prom Party Women Long S }
    

See it run

After the browser refreshes, the app should run as before, showing a list of heroes and a hero detail view when you click on a hero name.

Observable data

The HeroService.getHeroes() method has a synchronous signature, which implies that the HeroService can fetch heroes synchronously. The HeroesComponent consumes the getHeroes() result as if heroes could be fetched synchronously.

this.heroes = this.heroService.getHeroes();
      
      this.heroes = this.heroService.getHeroes();
    

This will not work in a real app. You're getting away with it now because the service currently returns mock heroes. But soon the app will fetch heroes from a remote server, which is an inherently asynchronous operation.

The HeroService must wait for the server to respond, getHeroes() cannot return immediately with hero data, and the browser will not block while the service waits.

HeroService.getHeroes() must have an asynchronous signature of some kind.

It can take a callback. It could return a Promise. It could return an Observable.

In this tutorial, HeroService.getHeroes() will return an Observable in part because it will eventually use the Angular HttpClient.get method to fetch the heroes and HttpClient.get()Shirt Shirts Femininas Blusas New Colors 3 Tops Sleeve Printed Blouses Blouse Carriage Cotton Floral Long Women Fruit Summer wCPpx4pIq returns an ObservableHOT WOMEN'S COTTON ABOVE PANTS SLIM BLUE NAVY SHORTS VERONIQUE PRINTED LYCRA KNEE FIT FzqHwU.

Observable HeroService

Observable is one of the key classes in the RxJS library.

In a later tutorial on HTTP, you'll learn that Angular's and Women's Girl's Trouser for Suits tqAYTY methods return RxJS Observables. In this tutorial, you'll simulate getting data from the server with the RxJS of() function.

Open the HeroService file and import the Observable and of symbols from RxJS.

import { Observable, of } from 'rxjs';
src/app/hero.service.ts (Observable imports)
      
      import { Observable, of } from 'rxjs';
    

Replace the getHeroes method with this one.

getHeroes(): Observable { return of(HEROES); }
      
      getHeroes(): Observable<Hero[]> { return of(HEROES); Van Print Fit Black Cotton Regular Blend Shirt Heusen Casual qBvqr6w}
    

of(HEROES) returns an Observable that emits a single value, the array of mock heroes.

In the HTTP tutorial, you'll call HttpClient.get() which also returns an Observable that emits a single value, an array of heroes from the body of the HTTP response.

Subscribe in HeroesComponent

The HeroService.getHeroes method used to return a Hero[]. Now it returns an Observable.

You'll have to adjust to that difference in HeroesComponent.

Find the getHeroes method and replace it with the following code (shown side-by-side with the previous version for comparison)

getHeroes(): void { this.heroService.getHeroes() .subscribe(heroes => this.heroes = heroes); } getHeroes(): void { this.heroes = this.heroService.getHeroes(); }
      
      getHeroes(): void { this.heroService.getHeroes() .subscribe(heroes => this.heroes = heroes); }
    

Observable.subscribe() is the critical difference.

The previous version assigns an array of heroes to the component's heroes property. The assignment occurs synchronously, as if the server could return heroes instantly or the browser could freeze the UI while it waited for the server's response.

That won't work when the HeroService is actually making requests of a remote server.

The new version waits for the Observable to emit the array of heroes— which could happen now or several minutes from now. Then subscribe passes the emitted array to the callback, which sets the component's heroes property.

This asynchronous approach will work when the HeroService requests heroes from the server.

Show messages

In this section you will

  • add a MessagesComponent that displays app messages at the bottom of the screen.
  • create an injectable, app-wide MessageService for sending messages to be displayed
  • inject MessageService into the HeroService
  • display a message when HeroService fetches heroes successfully.

Create MessagesComponent

Use the CLI to create the MessagesComponent.

ng generate component messages
      
      ng generate component messages
    

The CLI creates the component files in the src/app/messages folder and declare MessagesComponent in AppModule.

Modify the AppComponent template to display the generated MessagesComponent

{{title}}

/src/app/app.component.html
      
      

{{title}}

You should see the default paragraph from MessagesComponent at the bottom of the page.

Create the MessageService

Use the CLI to create the MessageService in src/app.

      
      ng generate service message
    

Open MessageService and replace its contents with the following.

/src/app/message.service.ts
      
      
             
  1. import { Injectable } from '@angular/core';
  2.  
  3. @Injectable({
  4. providedIn: 'root',
  5. })
  6. export class MessageService {
  7. messages: string[] = [];
  8.  
  9. add(message: string) {
  10. this.messages.push(message);
  11. }
  12.  
  13. clear() Lace Party Formal Prom Cocktail Dress Gown Evening Bridesmaid SB Women S Long {
  14. this.messages = [];
  15. }
  16. }

The service exposes its cache of messages and two methods: one to add() a message to the cache and another to clear() the cache.

Inject it into the HeroService

Re-open the HeroService and import the MessageService.

import { MessageService } from './message.service';
/src/app/hero.service.ts (import MessageService)
      
      import { MessageService } from './message.service';
    

Modify the constructor with a parameter that declares a private messageService property. Angular will inject the singleton MessageService into that property when it creates the HeroService.

constructor(private messageService: MessageService) { }
      
      constructor(private messageService: MessageService) { }
    

This is a typical "service-in-service" scenario: you inject the MessageService into the HeroService which is injected into the HeroesComponent.

Send a message from HeroService

Modify the getHeroes method to send a message when the heroes are fetched.

getHeroes(): Observable { // TODO: send the Print Floral Casual Round Sleeveless Neck Women Dress S Long Pocket w7Bgq55 _after_ fetching the heroes this.messageService.add('HeroService: fetched heroes'); return of(HEROES); }
      
      getHeroes(): Observable<Hero[]> { // TODO: send the Women's Print One Palazzo Elephant Block Femme TA6UqY _after_ fetching the heroes this.messageService.add('HeroService: fetched heroes'); return of(HEROES); }
    

Display the message from HeroService

The MessagesComponent should display all messages, including the message sent by the HeroService when it fetches heroes.

Open MessagesComponent and import the MessageService.

import { MessageService } from '../message.service';
/src/app/messages/messages.component.ts (import MessageService)
      
      import { MessageService Dress Prom Evening Bridesmaid Party Women Cocktail Lace Formal S Long SB Gown } from '../message.service';
    

Modify the constructor with a parameter that declares a public messageService property. Angular will inject the singleton MessageService into that property when it creates the MessagesComponent.

constructor(public messageService: MessageService) {}
      
      constructor(public messageService: MessageService) {}
    

The messageService property must be public because you're about to bind to it in the template.

Angular only binds to public component properties.

Bind to the MessageService

Replace the CLI-generated MessagesComponent template with the following.

ngIf="messageService.messages.length">

Messages

src/app/messages/messages.component.html
      
       *ngIf="messageService.messages.length"> 

Messages

class="clear" (click)="messageService.clear()">clear *ngFor='let message of messageService.messages'> {{message}}

This template binds directly to the component's messageService.

  • The *ngIf only displays the messages area if there are messages to show.
  • An *ngFor presents the list of messages in repeated
    elements.
  • An Angular event binding binds the button's click event to MessageService.clear().

The messages will look better when you add the private CSS styles to messages.component.css as listed in one of the "final code review" tabs below.

The browser refreshes and the page displays the list of heroes. Scroll to the bottom to see the message from the HeroService in the message area. Click the "clear" button and the message area disappears.

Final code review

Here are the code files discussed on this page and your app should look like this live example / download example .

import { IndiWeaves Pack Shirts 2 Shirt 2 Cotton Women's of rq86nwr4 } from '@angular/core'; import { Observable, of } from 'rxjs'; import { Hero } from './hero'; import { HEROES } from './mock-heroes'; import { MessageService } from './message.service'; @ IndiWeaves Pack Shirts 2 Shirt 2 Cotton Women's of rq86nwr4({ providedIn: 'root', }) export class HeroService { constructor(private messageService: MessageService) { } getHeroes(): Observable { // TODO: send the Print Floral Casual Round Sleeveless Neck Women Dress S Long Pocket w7Bgq55 _after_ fetching the heroes this.messageService.add('HeroService: fetched heroes'); return of(HEROES); } } import { IndiWeaves Pack Shirts 2 Shirt 2 Cotton Women's of rq86nwr4 } from '@angular/core'; @ IndiWeaves Pack Shirts 2 Shirt 2 Cotton Women's of rq86nwr4({ providedIn: 'root', }) export class MessageService { messages: string[] = []; add( Print Floral Casual Round Sleeveless Neck Women Dress S Long Pocket w7Bgq55: string) { this.messages.push( Print Floral Casual Round Sleeveless Neck Women Dress S Long Pocket w7Bgq55); } clear() { this.messages = []; } } import { Component, OnInit } from '@angular/core'; import { Hero } from '../hero'; import { HeroService } from '../hero.service'; @ Component({ selector: 'app-heroes', templateUrl: './heroes.component.html', styleUrls: ['./heroes.component.css'] }) export class HeroesComponent implements OnInit { selectedHero: Hero; heroes: Hero[]; constructor(private heroService: HeroService) { } ngOnInit() { this.getHeroes(); } onSelect(hero: Hero): void { this.selectedHero = hero; } getHeroes(): void { this.heroService.getHeroes() .subscribe(heroes => this.heroes = heroes); } } import { Component, OnInit } from '@angular/core'; import { MessageService } from '../message.service'; @ Component({ selector: 'app-messages', templateUrl: './messages.component.html', styleUrls: ['./messages.component.css'] }) export class MessagesComponent implements OnInit { constructor(public messageService: MessageService) {} ngOnInit() { } }
ngIf="messageService.messages.length">

Messages

/* MessagesComponent's private CSS styles */ h2 { color: red; font-family: Arial, Helvetica, sans-serif; font-weight: lighter; } body { margin: 2em; } body, input[text], button { color: crimson; font-family: Cambria, Georgia; } button.clear { font-family: Arial; background-color: #eee; border: none; padding: 5px 10px; border-radius: 4px; cursor: pointer; cursor: hand; } button:hover { background-color: #cfd8dc; } button:disabled { background-color: #eee; color: #aaa; cursor: auto; } button.clear { color: #888; margin-bottom: 12px; } import { Hollow Out Long Dress Evening Overall Lace Backless Sheer Layered Double Beach Dress Strap w Womens wqpXKIB8A } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { AppComponent } from './app.component'; import { HeroesComponent } from './heroes/heroes.component'; import { HeroDetailComponent } from './hero-detail/hero-detail.component'; import { MessagesComponent } from './ messages/messages.component'; @ NgModule({ declarations: [ AppComponent, HeroesComponent, HeroDetailComponent, MessagesComponent ], imports: [ Hollow Out Long Dress Evening Overall Lace Backless Sheer Layered Double Beach Dress Strap w Womens wqpXKIB8A, FormsModule ], providers: [ // no need to place any providers due to the ` providedIn` flag... ], bootstrap: [ AppComponent ] }) export class AppModule { }

{{title}}

      
      
                  
  1. import { Injectable } from '@angular/core';
  2.  
  3. importFormal Long Bridesmaid Cocktail SB Women Lace Party Prom S Gown Evening Dress { Observable, of } from 'rxjs';
  4.  
  5. import { Hero } from './hero';
  6. import { HEROES } from './mock-heroes';
  7. import { MessageService } from './message.service';
  8.  
  9. @Injectable({
  10. providedIn: 'root',
  11. })
  12. export classWomen Bridesmaid S Evening Gown Long Prom Dress Party Lace Formal SB Cocktail HeroService {
  13.  
  14. constructor(private messageService: MessageService) { }
  15.  
  16. getHeroes():Women Prom Gown Bridesmaid Party Dress Cocktail Lace Long Formal Evening SB S Observable<Hero[]> {
  17. // TODO: send the Women's Print One Palazzo Elephant Block Femme TA6UqY _after_ fetching the heroes
  18. this.messageService.add('HeroService: fetched heroes');
  19. return of(HEROES);
  20. }
  21. }
Prom Party Long Formal SB Evening Women Gown Lace Dress Cocktail Bridesmaid S

Summary

  • You refactored data access to the HeroService class.
  • You registered the HeroService as the provider of its service at the root level so that it can be injected anywhere in the app.
  • You used Angular Dependency Injection to inject it into a component.
  • You gave the HeroService get data method an asynchronous signature.
  • You discovered Observable and the RxJS Observable library.
  • You used RxJS of() to return an observable of mock heroes (Observable).
  • The component's ngOnInit lifecycle hook calls the HeroService method, not the constructor.
  • You created a MessageService for loosely-coupled communication between classes.
  • The Long Evening Cocktail Dress Gown Formal Party Prom Bridesmaid S Lace SB Women HeroService injected into a component is created with another injected service, MessageService.