Assignment #14 - Converting the HTTP call into an Angualr Service Open Command Prompt making sure you are in the C:\Humor folder enter the command: ng generate service humor Angular will create a Service, but no HTML/CSS files you will get these messages: C:\Humor>ng generate service humor CREATE src/app/humor.service.spec.ts (352 bytes) CREATE src/app/humor.service.ts (134 bytes) notice there are no changes to src/app.module.ts Now we are going to move the HTTP call out of the menu component and into the new Humor Service Steps: 1) It is always a good idea to design before you code, Angular has an Interface type which allows me to list the fields and methods a service will have 2) Create a new file in Visual Code, put it into the src/app folder and name it: humorHttp.ts this will be the Interface to the Http service, we will be adding methods to this interface in the next few assignments put this code into humorHttp.ts: import { Observable } from 'rxjs'; import { Category } from './category'; export interface humorHttp { getCategories(): Observable; } 3) Please notice our new Interface lists a single method, that take no parameters and returns Observable (an Observable of Category Array) which is what we need to build the menu component 4) Next we will modify the newly built Humor Service to implement this Interface 5) Open the src/app/humor.service.ts file in Visual Code, and replace the current contents with: import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; import { map } from "rxjs/operators"; import { Category } from './category'; import { humorHttp} from './humorHttp'; @Injectable({ providedIn: 'root' }) export class HumorService implements humorHttp { private humorRestURL = 'http://localhost:8080/HumorREST/api'; private categoryListURL = '/category/list'; constructor(private http: HttpClient) { } getCategories(): Observable { return this.http.get(this.humorRestURL + this.categoryListURL) .pipe(map((response : any) => { return JSON.parse(JSON.stringify(response)).categories.map((category : Category) => { return new Category( category.type, category.name, category.description, category.id); }); })) } } 6) Let's explore this code.... the imports tell Typescript which classes/methods we are going to use notice the import from rxjs. Rxjs is the React Library for JavaScript, and we use it to handle the asynchronous calles we will make to the REST Web Service Notice the Decorator of @Injectable (in the root of our Angular application) this allows Angular to inject (Dependency Injection) this service into the components that need it Notice the class implements the Interface, and we will code the required method(s) here Notice the constructor asks Angular to inject the built-in HttpClient (service) into this class The real work occurs in the getCategories method: here are the parts: getCategories(): Observable { <= this sets the input parameters (empty) ... and the return type (Observable) } return this.http.get(this.humorRestURL + this.categoryListURL) <= here is the URL for the .pipe(.... REST Web Service call the .pipe combines operations into a single result map((response : any) => { return JSON.parse(JSON.stringify(response)).categories.map((category : Category) => { return new Category( category.type, category.name, category.description, category.id); }); <= this set of commands loops thru the response (map) converts the response to a JSON string then parse it, to pull out the categories object then categories.map loops thru each category and builds a Typescript Category object 7) Now we go the the menu.componet.ts file and remove teh existing Http call and replace it with a call to our service, but we will need to import the service and get it injected into the component the complete menu.component.ts looks like: import { Component, OnInit } from '@angular/core'; import { HumorService } from '../humor.service'; <= notice the imports import { Category } from '../category'; @Component({ selector: 'app-menu', templateUrl: './menu.component.html', styleUrls: ['./menu.component.css'] }) export class MenuComponent implements OnInit { data : Category[] = []; constructor(private humorService : HumorService) { } <= notice the construcor injection ngOnInit(): void { this.humorService.getCategories() .subscribe(results => { this.data = results; }); } } 8) Save everything and run: ng serve notice we did not change the menu.component.html file, we are still using the field named data in the component we just changed the type to Category[]