import { HttpClient , HttpErrorResponse } from '@angular/common/http' ; import { Injectable } from '@angular/core' ; import { BehaviorSubject , Observable , ReplaySubject , throwError } from 'rxjs' ; import { catchError , combineLatest , finalize , tap } from 'rxjs/operators' ; import { Hero , ToastService } from '../core' ; import { FilterObserver } from '../shared/filter' ; const api = '/api' ; @ Injectable ( { providedIn : 'root' } ) export class HeroService { private heroes : Hero [ ] = [ ] ; filterObserver : FilterObserver ; filteredHeroes$ : Observable < Hero [ ] > ; heroes$ = new BehaviorSubject < Hero [ ] > ( [ ] ) ; constructor ( private http , private toastService ) { this . wireFilteredHeroes ( ) ; } /** Updates cached heroes and push into the observable */ private next ( newHeroes ) { this . heroes = newHeroes ; this . heroes$ . next ( newHeroes ) ; } /** Get all heroes from the database. Update heroes$ . */ getHeroes ( ) { this . http . get < Hero [ ] > ( `${ api }/heroes/` ) . pipe ( tap ( results => { this . next ( results ) ; this . toast ( 'Heroes retrieved successfully!' , 'GET' ) ; } ) , catchError ( this . handleError ) ) . subscribe ( ) ; } /** Add hero to the database. Update heroes$. */ addHero ( hero ) { this . http . post < Hero > ( `${ api }/hero/` , hero ) . pipe ( tap ( added => { this . next ( this . heroes . concat ( added ) ) ; this . toast ( `Hero ${ hero . name } added` , 'POST' ) ; } ) , catchError ( this . handleError ) ) . subscribe ( ) ; } /** Delete hero-by-id from the database. Update heroes$. */ deleteHero ( hero ) { const id = hero && hero . id ; this . next ( this . heroes . filter ( h => h . id !== id ) ) ; this . toast ( `Hero ${ hero . name } deleted` , 'DELETE' ) ; this . http . delete ( `${ api }/hero/${ id }` ) . pipe ( catchError ( this . handleError ) ) . subscribe ( ) ; } /** Update the hero in the database.  Update heroes$. */ updateHero ( updatedHero ) { const id = updatedHero && updatedHero . id ; this . http . put < Hero > ( `${ api }/hero/${ updatedHero . id }` , updatedHero ) . pipe ( tap ( updated => { this . next ( this . heroes . map ( h => ( h . id === id ? updatedHero : h ) ) ) ; this . toast ( `Hero ${ updatedHero . name } updated` , 'PUT' ) ; } ) , catchError ( this . handleError ) ) . subscribe ( ) ; } private handleError ( res ) { console . error ( res . error ) ; return throwError ( res . error || 'Server error' ) ; } private toast ( message , action ) { this . toastService . openSnackBar ( message , action ) ; } wireFilteredHeroes ( ) { const filterObserver = new ReplaySubject < string > ( ) ; filterObserver . next ( 'm' ) ; this . filterObserver = { filter$ : filterObserver . asObservable ( ) , setFilter : filterValue => filterObserver . next ( filterValue ) } ; this . filteredHeroes$ = this . filterObserver . filter$ . pipe ( combineLatest ( this . heroes$ , this . filterProjector ) ) ; } filterProjector ( filterValue , entities ) { const regEx = filterValue ? new RegExp ( filterValue , 'i' ) : undefined ; return regEx ? entities . filter ( ( e ) => e . name && e . name . match ( regEx ) ) : entities ; } }