diff --git a/app/app.module.ts b/app/app.module.ts
index 627ef1c..ccbfb20 100644
--- a/app/app.module.ts
+++ b/app/app.module.ts
@@ -1,3 +1,5 @@
+import "./rxjs-extensions";
+
import { NgModule } from "@angular/core";
import { BrowserModule } from "@angular/platform-browser";
import { FormsModule } from "@angular/forms";
@@ -12,6 +14,7 @@ import { AppComponent } from "./app.component";
import { DucksComponent } from "./ducks.component";
import { DuckDetailComponent } from "./duck-detail.component";
import { DashboardComponent } from "./dashboard.component";
+import { DuckSearchComponent } from "./duck-search.component";
import { DuckService } from "./duck.service";
@@ -27,6 +30,7 @@ import { DuckService } from "./duck.service";
AppComponent,
DucksComponent,
DuckDetailComponent,
+ DuckSearchComponent,
DashboardComponent
],
providers: [ DuckService ],
diff --git a/app/dashboard.component.html b/app/dashboard.component.html
index 5071720..89ac14c 100644
--- a/app/dashboard.component.html
+++ b/app/dashboard.component.html
@@ -1,3 +1,4 @@
{{ duck.color }}
+
diff --git a/app/duck-search.component.html b/app/duck-search.component.html
new file mode 100644
index 0000000..dc408d7
--- /dev/null
+++ b/app/duck-search.component.html
@@ -0,0 +1,11 @@
+
diff --git a/app/duck-search.component.ts b/app/duck-search.component.ts
new file mode 100644
index 0000000..6771cdb
--- /dev/null
+++ b/app/duck-search.component.ts
@@ -0,0 +1,43 @@
+import { Component, OnInit } from "@angular/core";
+import { Router } from "@angular/router";
+import { Observable } from "rxjs/Observable";
+import { Subject } from "rxjs/Subject";
+
+import { DuckSearchService } from "./duck-search.service";
+import { Duck } from "./models";
+
+@Component({
+ selector: "duck-search",
+ templateUrl: "/app/duck-search.component.html",
+ providers: [ DuckSearchService ]
+})
+export class DuckSearchComponent implements OnInit {
+ ducks: Observable;
+ private searchTerm = new Subject();
+
+ constructor(private duckSearchService: DuckSearchService,
+ private router: Router)
+ {}
+
+ search(term: string): void {
+ this.searchTerm.next(term);
+ }
+
+ ngOnInit(): void {
+ this.ducks = this.searchTerm
+ .debounceTime(300) // wait for 300ms pause in events
+ .distinctUntilChanged() // ignore if next search term is same as previous
+ .switchMap(term => term // switch to new observable each time
+ ? this.duckSearchService.search(term)
+ : Observable.of([]))
+ .catch(error => {
+ console.log(error);
+ return Observable.of([]);
+ });
+ }
+
+ gotoDetail(duck: Duck): void {
+ let link = ['/detail', duck.id];
+ this.router.navigate(link);
+ }
+}
diff --git a/app/duck-search.service.ts b/app/duck-search.service.ts
new file mode 100644
index 0000000..736dcac
--- /dev/null
+++ b/app/duck-search.service.ts
@@ -0,0 +1,15 @@
+import { Injectable } from "@angular/core";
+import { Http, Response } from "@angular/http";
+import { Observable } from "rxjs";
+
+import { Duck } from "./models";
+
+@Injectable()
+export class DuckSearchService {
+ constructor (private http: Http) {}
+
+ search(term: string): Observable {
+ return this.http.get(`app/ducks/?color=${term}`)
+ .map((r: Response) => r.json().data as Duck[]);
+ }
+}
diff --git a/app/rxjs-extensions.ts b/app/rxjs-extensions.ts
new file mode 100644
index 0000000..2bb03c8
--- /dev/null
+++ b/app/rxjs-extensions.ts
@@ -0,0 +1,12 @@
+// Observable class extensions
+import "rxjs/add/observable/of";
+import "rxjs/add/observable/throw";
+
+// Observable operators
+import "rxjs/add/operator/catch";
+import "rxjs/add/operator/debounceTime";
+import "rxjs/add/operator/distinctUntilChanged";
+import "rxjs/add/operator/do";
+import "rxjs/add/operator/filter";
+import "rxjs/add/operator/map";
+import "rxjs/add/operator/switchMap";