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
+
+
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.