This repository has been archived by the owner on Dec 4, 2017. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 880
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
docs(rxjs): Added developer guide on Observables
- Loading branch information
1 parent
35bbeb2
commit 17618d1
Showing
24 changed files
with
788 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
'use strict'; // necessary for es6 output in node | ||
|
||
import { browser | ||
/*, element, by, ElementFinder*/ | ||
} from 'protractor'; | ||
|
||
describe('RxJS', function () { | ||
|
||
beforeAll(function () { | ||
browser.get(''); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
<h2>ADD HERO</h2> | ||
<form [formGroup]="form" (ngSubmit)="save(form.value)"> | ||
<p> | ||
*Name: <input type="text" formControlName="name"><br> | ||
<span *ngIf="showErrors && form.get('name').errors" class="error">Name is required</span> | ||
</p> | ||
<p> | ||
Description: <input type="text" formControlName="description"> | ||
</p> | ||
<p> | ||
<button type="submit" [disabled]="showErrors">Save</button> | ||
</p> | ||
</form> | ||
|
||
<span *ngIf="success">The hero has been added</span> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// #docplaster | ||
// #docregion | ||
import 'rxjs/add/observable/of'; | ||
import 'rxjs/add/observable/fromEvent'; | ||
import 'rxjs/add/observable/merge'; | ||
import 'rxjs/add/observable/of'; | ||
import 'rxjs/add/operator/debounceTime'; | ||
import 'rxjs/add/operator/do'; | ||
import { Component, OnInit, OnDestroy, AfterViewInit, ViewChildren, ElementRef } from '@angular/core'; | ||
import { FormBuilder, FormGroup, FormControlName, Validators } from '@angular/forms'; | ||
import { Observable } from 'rxjs/Observable'; | ||
import { Subscription } from 'rxjs/Subscription'; | ||
|
||
import { HeroService } from './hero.service'; | ||
|
||
@Component({ | ||
moduleId: module.id, | ||
templateUrl: 'add-hero.component.html', | ||
styles: [ '.error { color: red }' ] | ||
}) | ||
export class AddHeroComponent implements OnInit, OnDestroy, AfterViewInit { | ||
@ViewChildren(FormControlName, { read: ElementRef }) formControls: ElementRef[]; | ||
|
||
form: FormGroup; | ||
sub: Subscription; | ||
showErrors: boolean = false; | ||
submitted: boolean = false; | ||
success: boolean; | ||
|
||
constructor( | ||
private formBuilder: FormBuilder, | ||
private heroService: HeroService | ||
) {} | ||
|
||
ngOnInit() { | ||
this.form = this.formBuilder.group({ | ||
name: ['', [Validators.required]], | ||
description: [''] | ||
}); | ||
} | ||
|
||
ngAfterViewInit() { | ||
const controlBlurs: Observable<Event>[] = this.formControls.map(field => Observable.fromEvent(field.nativeElement, 'blur')); | ||
|
||
this.sub = Observable.merge( | ||
this.form.valueChanges, | ||
...controlBlurs | ||
) | ||
.debounceTime(300) | ||
.subscribe(() => this.checkErrors()); | ||
} | ||
|
||
checkErrors() { | ||
if (!this.form.valid) { | ||
this.showErrors = true; | ||
} | ||
} | ||
|
||
save(model: any) { | ||
this.success = false; | ||
this.submitted = true; | ||
|
||
this.heroService.addHero(model) | ||
.do(() => { | ||
this.success = true; | ||
this.submitted = false; | ||
}) | ||
.subscribe(); | ||
} | ||
|
||
ngOnDestroy() { | ||
this.sub.unsubscribe(); | ||
} | ||
} |
34 changes: 34 additions & 0 deletions
34
public/docs/_examples/rxjs/ts/app/api-error-handler.service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { Injectable } from '@angular/core'; | ||
import { Response } from '@angular/http'; | ||
import { Observable } from 'rxjs/Observable'; | ||
|
||
export interface ApiError { | ||
message: string; | ||
} | ||
|
||
@Injectable() | ||
export class ApiErrorHandlerService { | ||
handle(resp: Response): Observable<Error> { | ||
return Observable.of(resp) | ||
.switchMap(response => { | ||
|
||
let error: ApiError; | ||
|
||
try { | ||
error = response.json().error; | ||
} catch (e) { | ||
if (response.status === 404) { | ||
error = { | ||
message: 'The requested resource was not found' | ||
}; | ||
} else { | ||
error = { | ||
message: 'An unknown error has occurred' | ||
}; | ||
} | ||
} | ||
|
||
return Observable.throw(error); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// #docplaster | ||
// #docregion | ||
import { NgModule } from '@angular/core'; | ||
import { RouterModule, Routes } from '@angular/router'; | ||
import { AddHeroComponent } from './add-hero.component'; | ||
import { HeroDetailComponent } from './hero-detail.component'; | ||
import { HeroSearchComponent } from './hero-search.component'; | ||
import { HeroListComponent } from './hero-list.component'; | ||
|
||
const appRoutes: Routes = [ | ||
{ path: 'heroes/add', component: AddHeroComponent }, | ||
{ path: 'heroes/search', component: HeroSearchComponent }, | ||
{ path: 'heroes', component: HeroListComponent }, | ||
{ path: 'hero/:id', component: HeroDetailComponent }, | ||
{ path: '', redirectTo: '/heroes', pathMatch: 'full' }, | ||
]; | ||
|
||
@NgModule({ | ||
imports: [RouterModule.forRoot(appRoutes)], | ||
exports: [RouterModule] | ||
}) | ||
export class AppRoutingModule {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// #docplaster | ||
// #docregion | ||
import { Component } from '@angular/core'; | ||
|
||
@Component({ | ||
selector: 'my-app', | ||
template: ` | ||
<h1 class="title">RxJS in Angular</h1> | ||
<a routerLink="/heroes">Heroes</a><br> | ||
<a routerLink="/heroes/add">Add Hero</a><br> | ||
<a routerLink="/heroes/search">Hero Search</a> | ||
<router-outlet></router-outlet> | ||
<loading-component></loading-component> | ||
` | ||
}) | ||
export class AppComponent { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// #docregion | ||
import { NgModule } from '@angular/core'; | ||
import { BrowserModule } from '@angular/platform-browser'; | ||
import { HttpModule } from '@angular/http'; | ||
import { ReactiveFormsModule } from '@angular/forms'; | ||
|
||
import { AppComponent } from './app.component'; | ||
import { AppRoutingModule } from './app-routing.module'; | ||
import { AddHeroComponent } from './add-hero.component'; | ||
import { LoadingComponent } from './loading.component'; | ||
import { HeroSearchComponent } from './hero-search.component'; | ||
import { HeroDetailComponent } from './hero-detail.component'; | ||
import { HeroListComponent } from './hero-list.component'; | ||
|
||
import { LoadingService } from './loading.service'; | ||
import { HeroService } from './hero.service'; | ||
|
||
// Imports for loading & configuring the in-memory web api | ||
import { InMemoryWebApiModule } from 'angular-in-memory-web-api'; | ||
import { InMemoryDataService } from './in-memory-data.service'; | ||
import { ApiErrorHandlerService } from './api-error-handler.service'; | ||
|
||
@NgModule({ | ||
imports: [ | ||
BrowserModule, | ||
HttpModule, | ||
AppRoutingModule, | ||
ReactiveFormsModule, | ||
InMemoryWebApiModule.forRoot(InMemoryDataService) | ||
], | ||
declarations: [ | ||
AppComponent, | ||
AddHeroComponent, | ||
LoadingComponent, | ||
HeroSearchComponent, | ||
HeroDetailComponent, | ||
HeroListComponent | ||
], | ||
providers: [ | ||
HeroService, | ||
LoadingService, | ||
ApiErrorHandlerService | ||
], | ||
bootstrap: [ AppComponent ] | ||
}) | ||
export class AppModule { | ||
} | ||
// #enddocregion |
27 changes: 27 additions & 0 deletions
27
public/docs/_examples/rxjs/ts/app/event-aggregator.service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { Injectable } from '@angular/core'; | ||
import { BehaviorSubject } from 'rxjs/BehaviorSubject'; | ||
|
||
export interface AppEvent { | ||
type: string; | ||
message: string; | ||
} | ||
|
||
@Injectable() | ||
export class EventAggregatorService { | ||
_events: AppEvent[]; | ||
events$: BehaviorSubject<AppEvent[]> = new BehaviorSubject<any>([]); | ||
|
||
add(event: AppEvent) { | ||
this._events.push(event); | ||
this.next(); | ||
} | ||
|
||
clear() { | ||
this._events = []; | ||
this.next(); | ||
} | ||
|
||
next() { | ||
this.events$.next(this._events); | ||
} | ||
} |
57 changes: 57 additions & 0 deletions
57
public/docs/_examples/rxjs/ts/app/hero-detail.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// #docplaster | ||
// #docregion | ||
import 'rxjs/add/observable/of'; | ||
import 'rxjs/add/operator/map'; | ||
import 'rxjs/add/operator/do'; | ||
import 'rxjs/add/operator/filter'; | ||
import { Component, OnInit } from '@angular/core'; | ||
import { ActivatedRoute, Params } from '@angular/router'; | ||
import { HeroService } from './hero.service'; | ||
import { Hero } from './hero'; | ||
import { Observable } from 'rxjs/Observable'; | ||
|
||
@Component({ | ||
template: ` | ||
<div *ngIf="loading"> | ||
Loading Hero... | ||
</div> | ||
<div *ngIf="hero"> | ||
<h3>HEROES</h3> | ||
<div> | ||
<label>Id: </label>{{ hero.id }} | ||
</div> | ||
<div> | ||
<label>Name: </label> | ||
<input placeholder="name" [value]="hero.name"/> | ||
</div> | ||
</div> | ||
<div *ngIf="error"> | ||
No hero found | ||
</div> | ||
` | ||
}) | ||
export class HeroDetailComponent implements OnInit { | ||
hero: Hero; | ||
loading: boolean = true; | ||
error: boolean; | ||
|
||
constructor( | ||
private heroService: HeroService, | ||
private route: ActivatedRoute | ||
) {} | ||
|
||
ngOnInit() { | ||
this.route.params | ||
.do(() => this.loading = true) | ||
.switchMap((params: Params) => | ||
this.heroService.getHero(params['id']) | ||
.catch(error => { | ||
this.error = true; | ||
|
||
return Observable.of(null); | ||
}) | ||
) | ||
.do(() => this.loading = false) | ||
.subscribe((hero: Hero) => this.hero = hero); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// #docplaster | ||
// #docregion | ||
import 'rxjs/add/operator/toPromise'; | ||
import { Component, OnInit } from '@angular/core'; | ||
|
||
import { HeroService } from './hero.service'; | ||
import { Hero } from './hero'; | ||
|
||
@Component({ | ||
template: ` | ||
<h2>HEROES</h2> | ||
<ul class="items"> | ||
<li *ngFor="let hero of heroes"> | ||
<span class="badge">{{ hero.id }}</span> {{ hero.name }} | ||
</li> | ||
</ul> | ||
` | ||
}) | ||
export class HeroListComponent implements OnInit { | ||
heroes: Hero[]; | ||
|
||
constructor( | ||
private service: HeroService | ||
) {} | ||
|
||
ngOnInit() { | ||
this.service.getHeroes() | ||
.subscribe(heroes => this.heroes = heroes); | ||
} | ||
} | ||
// #enddocregion |
16 changes: 16 additions & 0 deletions
16
public/docs/_examples/rxjs/ts/app/hero-search.component.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
/* #docregion */ | ||
.search-result{ | ||
border-bottom: 1px solid gray; | ||
border-left: 1px solid gray; | ||
border-right: 1px solid gray; | ||
width:195px; | ||
height: 20px; | ||
padding: 5px; | ||
background-color: white; | ||
cursor: pointer; | ||
} | ||
|
||
.search-box{ | ||
width: 200px; | ||
height: 20px; | ||
} |
12 changes: 12 additions & 0 deletions
12
public/docs/_examples/rxjs/ts/app/hero-search.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<!-- #docregion --> | ||
<div id="search-component"> | ||
<h2>HERO SEARCH</h2> | ||
<form [formGroup]="form"> | ||
<input formControlName="searchTerms" class="search-box" /> | ||
</form> | ||
<div> | ||
<div *ngFor="let hero of heroes$ | async" class="search-result"> | ||
<a [routerLink]="['/hero', hero.id]">{{ hero.name }}</a> | ||
</div> | ||
</div> | ||
</div> |
Oops, something went wrong.