From f9241e0057b4e7b901c41ed85a9925be70c2ee10 Mon Sep 17 00:00:00 2001 From: Olivier DOSSMANN Date: Mon, 28 Oct 2019 09:23:56 +0100 Subject: [PATCH] Angular Tour of Heroes: suite et fin ! --- angular-tour-of-heroes/src/app/app.module.ts | 4 +- .../app/dashboard/dashboard.component.html | 4 +- .../app/hero-search/hero-search.component.css | 39 ++++++++++++++++++ .../hero-search/hero-search.component.html | 13 ++++++ .../hero-search/hero-search.component.spec.ts | 25 ++++++++++++ .../app/hero-search/hero-search.component.ts | 40 +++++++++++++++++++ .../src/app/hero.service.ts | 11 +++++ 7 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 angular-tour-of-heroes/src/app/hero-search/hero-search.component.css create mode 100644 angular-tour-of-heroes/src/app/hero-search/hero-search.component.html create mode 100644 angular-tour-of-heroes/src/app/hero-search/hero-search.component.spec.ts create mode 100644 angular-tour-of-heroes/src/app/hero-search/hero-search.component.ts diff --git a/angular-tour-of-heroes/src/app/app.module.ts b/angular-tour-of-heroes/src/app/app.module.ts index 011092a..e440a4a 100644 --- a/angular-tour-of-heroes/src/app/app.module.ts +++ b/angular-tour-of-heroes/src/app/app.module.ts @@ -12,6 +12,7 @@ import { DashboardComponent } from './dashboard/dashboard.component'; import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api'; import { InMemoryDataService } from './in-memory-data.service'; +import { HeroSearchComponent } from './hero-search/hero-search.component'; @NgModule({ declarations: [ @@ -19,7 +20,8 @@ import { InMemoryDataService } from './in-memory-data.service'; HeroesComponent, HeroDetailComponent, MessagesComponent, - DashboardComponent + DashboardComponent, + HeroSearchComponent ], imports: [ BrowserModule, diff --git a/angular-tour-of-heroes/src/app/dashboard/dashboard.component.html b/angular-tour-of-heroes/src/app/dashboard/dashboard.component.html index 9827aff..b70c0c7 100644 --- a/angular-tour-of-heroes/src/app/dashboard/dashboard.component.html +++ b/angular-tour-of-heroes/src/app/dashboard/dashboard.component.html @@ -1,9 +1,11 @@

Top Heroes

+ routerLink="/detail/{{hero.id}}">

{{hero.name}}

+ + diff --git a/angular-tour-of-heroes/src/app/hero-search/hero-search.component.css b/angular-tour-of-heroes/src/app/hero-search/hero-search.component.css new file mode 100644 index 0000000..190d9bb --- /dev/null +++ b/angular-tour-of-heroes/src/app/hero-search/hero-search.component.css @@ -0,0 +1,39 @@ +/* HeroSearch private styles */ +.search-result li { + border-bottom: 1px solid gray; + border-left: 1px solid gray; + border-right: 1px solid gray; + width: 195px; + height: 16px; + padding: 5px; + background-color: white; + cursor: pointer; + list-style-type: none; +} + +.search-result li:hover { + background-color: #607D8B; +} + +.search-result li a { + color: #888; + display: block; + text-decoration: none; +} + +.search-result li a:hover { + color: white; +} +.search-result li a:active { + color: white; +} +#search-box { + width: 200px; + height: 20px; +} + + +ul.search-result { + margin-top: 0; + padding-left: 0; +} diff --git a/angular-tour-of-heroes/src/app/hero-search/hero-search.component.html b/angular-tour-of-heroes/src/app/hero-search/hero-search.component.html new file mode 100644 index 0000000..cce6288 --- /dev/null +++ b/angular-tour-of-heroes/src/app/hero-search/hero-search.component.html @@ -0,0 +1,13 @@ +
+

+ + + + +
diff --git a/angular-tour-of-heroes/src/app/hero-search/hero-search.component.spec.ts b/angular-tour-of-heroes/src/app/hero-search/hero-search.component.spec.ts new file mode 100644 index 0000000..901bb7f --- /dev/null +++ b/angular-tour-of-heroes/src/app/hero-search/hero-search.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HeroSearchComponent } from './hero-search.component'; + +describe('HeroSearchComponent', () => { + let component: HeroSearchComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HeroSearchComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HeroSearchComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/angular-tour-of-heroes/src/app/hero-search/hero-search.component.ts b/angular-tour-of-heroes/src/app/hero-search/hero-search.component.ts new file mode 100644 index 0000000..e2a1717 --- /dev/null +++ b/angular-tour-of-heroes/src/app/hero-search/hero-search.component.ts @@ -0,0 +1,40 @@ +import { Component, OnInit } from '@angular/core'; + +import { Observable, Subject } from 'rxjs'; + +import { + debounceTime, distinctUntilChanged, switchMap +} from 'rxjs/operators'; + +import { Hero } from '../hero'; +import { HeroService } from '../hero.service'; + +@Component({ + selector: 'app-hero-search', + templateUrl: './hero-search.component.html', + styleUrls: ['./hero-search.component.css'] +}) +export class HeroSearchComponent implements OnInit { + heroes$: Observable; + private searchTerms = new Subject(); + + constructor(private heroService: HeroService) { } + + // Push a search term into the observable stream. + search(term: string): void { + this.searchTerms.next(term); + } + + ngOnInit(): void { + this.heroes$ = this.searchTerms.pipe( + // wait 300ms after each keystroke before considering the term + debounceTime(300), + + // ignore new term if same as previous term + distinctUntilChanged(), + + // switch to new search observable each time the terme changes + switchMap((term: string) => this.heroService.searchHeroes(term)), + ); + } +} diff --git a/angular-tour-of-heroes/src/app/hero.service.ts b/angular-tour-of-heroes/src/app/hero.service.ts index 3e0e88f..567c266 100644 --- a/angular-tour-of-heroes/src/app/hero.service.ts +++ b/angular-tour-of-heroes/src/app/hero.service.ts @@ -67,6 +67,17 @@ export class HeroService { ); } + searchHeroes(term: string): Observable { + if (!term.trim()) { + // if not search term, return empty hero array. + return of([]); + } + return this.http.get(`${this.heroesUrl}/?name=${term}`).pipe( + tap(_ => this.log(`found heroes matching "${term}"`)), + catchError(this.handleError('searchHeroes', [])) + ); + } + /** * Handle Http operation that failed. * Let the app continue.