From: Kai Moritz Date: Sun, 31 May 2020 12:06:23 +0000 (+0200) Subject: 6: Get Data from a Server X-Git-Url: https://juplo.de/gitweb/?p=examples%2Fangular-tour-of-heroes;a=commitdiff_plain;h=b96b10a45927728a8e0c2234f494fb9eebd3df16 6: Get Data from a Server k) Search by name --- diff --git a/src/app/app.module.ts b/src/app/app.module.ts index cffb82a..c35475a 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -12,6 +12,7 @@ import { HeroesComponent } from './heroes/heroes.component'; import { HeroDetailComponent } from './hero-detail/hero-detail.component'; import { MessagesComponent } from './messages/messages.component'; import { DashboardComponent } from './dashboard/dashboard.component'; +import { HeroSearchComponent } from './hero-search/hero-search.component'; @NgModule({ declarations: [ @@ -19,7 +20,8 @@ import { DashboardComponent } from './dashboard/dashboard.component'; HeroesComponent, HeroDetailComponent, MessagesComponent, - DashboardComponent + DashboardComponent, + HeroSearchComponent ], imports: [ BrowserModule, diff --git a/src/app/dashboard/dashboard.component.html b/src/app/dashboard/dashboard.component.html index 1fc389b..c33213e 100644 --- a/src/app/dashboard/dashboard.component.html +++ b/src/app/dashboard/dashboard.component.html @@ -6,3 +6,6 @@ + + + diff --git a/src/app/hero-search/hero-search.component.css b/src/app/hero-search/hero-search.component.css new file mode 100644 index 0000000..190d9bb --- /dev/null +++ b/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/src/app/hero-search/hero-search.component.html b/src/app/hero-search/hero-search.component.html new file mode 100644 index 0000000..cce6288 --- /dev/null +++ b/src/app/hero-search/hero-search.component.html @@ -0,0 +1,13 @@ +
+

+ + + + +
diff --git a/src/app/hero-search/hero-search.component.spec.ts b/src/app/hero-search/hero-search.component.spec.ts new file mode 100644 index 0000000..901bb7f --- /dev/null +++ b/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/src/app/hero-search/hero-search.component.ts b/src/app/hero-search/hero-search.component.ts new file mode 100644 index 0000000..98a085e --- /dev/null +++ b/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 term changes + switchMap((term: string) => this.heroService.searchHeroes(term)), + ); + } +} diff --git a/src/app/hero.service.ts b/src/app/hero.service.ts index 349d043..b794b8a 100644 --- a/src/app/hero.service.ts +++ b/src/app/hero.service.ts @@ -57,6 +57,20 @@ export class HeroService { ); } + /* GET heroes whose name contains search term */ + 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(x => x.length ? + this.log(`found heroes matching "${term}"`) : + this.log(`no heroes matching "${term}"`)), + catchError(this.handleError('searchHeroes', [])) + ); + } + /** * Handle Http operation that failed. * Let the app continue.