Skip to content
This repository has been archived by the owner on Dec 4, 2017. It is now read-only.

[WIP] docs(rxjs): Added developer guide on RxJS #3047

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions public/docs/_examples/rxjs/e2e-spec.ts
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('');
});
});
Empty file.
10 changes: 10 additions & 0 deletions public/docs/_examples/rxjs/ts/plnkr.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"description": "RxJS",
"basePath": "src/",
"files":[
"!**/*.d.ts",
"!**/*.js",
"!**/*.[0-9].*"
],
"tags": ["rxjs", "observable"]
}
14 changes: 14 additions & 0 deletions public/docs/_examples/rxjs/ts/src/app/add-hero.component.1.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!-- #docregion -->
<h2>ADD HERO</h2>

<form [formGroup]="form" (ngSubmit)="save()" *ngIf="!success">
<p>
Name: <input type="text" formControlName="name"><br>
<span *ngIf="showErrors && form.hasError('required', ['name'])" class="error">Name is required</span>
</p>
<p>
<button type="submit" [disabled]="!form.valid">Save</button>
</p>
</form>

<span *ngIf="success">The hero has been added</span>
32 changes: 32 additions & 0 deletions public/docs/_examples/rxjs/ts/src/app/add-hero.component.1.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// #docplaster
// #docregion
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

import { HeroService } from './hero.service';

@Component({
moduleId: module.id,
templateUrl: './add-hero.component.html',
styles: [ '.error { color: red }' ]
})
export class AddHeroComponent implements OnInit {
form: FormGroup;
showErrors: boolean = false;
success: boolean;

constructor(
private formBuilder: FormBuilder,
private heroService: HeroService
) {}

ngOnInit() {
this.form = this.formBuilder.group({
name: ['', [Validators.required]]
});
}

save(model: any) {
// TODO: Save hero
}
}
14 changes: 14 additions & 0 deletions public/docs/_examples/rxjs/ts/src/app/add-hero.component.2.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!-- #docregion -->
<h2>ADD HERO</h2>

<form [formGroup]="form" (ngSubmit)="save()" *ngIf="!success">
<p>
Name: <input type="text" formControlName="name" #heroName><br>
<span *ngIf="showErrors && form.hasError('required', ['name'])" class="error">Name is required</span>
</p>
<p>
<button type="submit" [disabled]="!form.valid">Save</button>
</p>
</form>

<span *ngIf="success">The hero has been added</span>
74 changes: 74 additions & 0 deletions public/docs/_examples/rxjs/ts/src/app/add-hero.component.2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// #docplaster
// #docregion
// #docregion rxjs-imports-1
import 'rxjs/add/operator/takeUntil';
import 'rxjs/add/observable/merge';
import 'rxjs/add/observable/fromEvent';
// #enddocregion rxjs-imports-1
// #docregion viewchild-imports
import { Component, OnInit, OnDestroy, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
// #enddocregion viewchild-imports
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

import { Hero } from './hero';
import { HeroService } from './hero.service';

// #docregion rxjs-imports-2
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
// #enddocregion rxjs-imports-2

// #docregion viewchild-heroName
@Component({
moduleId: module.id,
templateUrl: './add-hero.component.html',
styles: [ '.error { color: red }' ]
})
export class AddHeroComponent implements OnInit, OnDestroy, AfterViewInit {
@ViewChild('heroName', { read: ElementRef }) heroName: ElementRef;
// #enddocregion viewchild-heroName

form: FormGroup;
showErrors: boolean = false;
success: boolean;
onDestroy$ = new Subject();

constructor(
private formBuilder: FormBuilder,
private heroService: HeroService
) {}

ngOnInit() {
this.form = this.formBuilder.group({
name: ['', [Validators.required]]
});
}
// #docregion observable-event
ngAfterViewInit() {
const controlBlur$: Observable<Event> = Observable.fromEvent(this.heroName.nativeElement, 'blur');

Observable.merge(
controlBlur$
)
.takeUntil(this.onDestroy$)
.subscribe(() => this.checkForm());
}

checkForm() {
if (!this.form.valid) {
this.showErrors = true;
}
}
// #enddocregion observable-event

ngOnDestroy() {
this.onDestroy$.complete();
}

save(model: Hero) {
this.heroService.addHero(model.name)
.subscribe(() => {
this.success = true;
});
}
}
16 changes: 16 additions & 0 deletions public/docs/_examples/rxjs/ts/src/app/add-hero.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!-- docregion -->
<h2>ADD HERO</h2>

<form [formGroup]="form" (ngSubmit)="save(form.value)" *ngIf="!success">
<p>
*Name: <input type="text" formControlName="name" #heroName><br>
<span *ngIf="showErrors && form.hasError('required', ['name'])" class="error">Name is required</span>
<span *ngIf="(form.get('name').statusChanges | async) === 'PENDING'" class="error">Checking if name is already taken</span>
<span *ngIf="showErrors && form.hasError('taken', ['name'])" class="error">Hero name is already taken</span>
</p>
<p>
<button type="submit" [disabled]="!form.valid">Save</button>
</p>
</form>

<span *ngIf="success">The hero has been added</span>
75 changes: 75 additions & 0 deletions public/docs/_examples/rxjs/ts/src/app/add-hero.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// #docplaster
// #docregion
// #docregion rxjs-imports-1
import 'rxjs/add/operator/takeUntil';
import 'rxjs/add/observable/merge';
import 'rxjs/add/observable/fromEvent';
// #enddocregion rxjs-imports-1
// #docregion viewchild-imports
import { Component, OnInit, OnDestroy, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
// #enddocregion viewchild-imports
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

import { Hero } from './hero';
import { HeroService } from './hero.service';

// #docregion rxjs-imports-2
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
// #enddocregion rxjs-imports-2

// #docregion viewchild-heroName
@Component({
moduleId: module.id,
templateUrl: './add-hero.component.html',
styles: [ '.error { color: red }' ]
})
export class AddHeroComponent implements OnInit, OnDestroy, AfterViewInit {
@ViewChild('heroName', { read: ElementRef }) heroName: ElementRef;
// #enddocregion viewchild-heroName

form: FormGroup;
showErrors: boolean = false;
success: boolean;
onDestroy$ = new Subject();

constructor(
private formBuilder: FormBuilder,
private heroService: HeroService
) {}

ngOnInit() {
this.form = this.formBuilder.group({
name: ['', [Validators.required]]
});
}
// #docregion value-changes
ngAfterViewInit() {
const controlBlur$: Observable<Event> = Observable.fromEvent(this.heroName.nativeElement, 'blur');

Observable.merge(
controlBlur$,
this.form.get('name').valueChanges
)
.takeUntil(this.onDestroy$)
.subscribe(() => this.checkForm());
}

checkForm() {
if (!this.form.valid) {
this.showErrors = true;
}
}
// #enddocregion value-changes

ngOnDestroy() {
this.onDestroy$.complete();
}

save(model: Hero) {
this.heroService.addHero(model.name)
.subscribe(() => {
this.success = true;
});
}
}
20 changes: 20 additions & 0 deletions public/docs/_examples/rxjs/ts/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// #docplaster
// #docregion
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HeroListComponent } from './hero-list.component';
import { HeroCounterComponent } from './hero-counter.component';
import { AddHeroComponent } from './add-hero.component';

const appRoutes: Routes = [
{ path: 'hero/add', component: AddHeroComponent },
{ path: 'hero/counter', component: HeroCounterComponent },
{ path: 'heroes', component: HeroListComponent },
{ path: '', redirectTo: '/heroes', pathMatch: 'full' },
];

@NgModule({
imports: [RouterModule.forRoot(appRoutes)],
exports: [RouterModule]
})
export class AppRoutingModule {}
36 changes: 36 additions & 0 deletions public/docs/_examples/rxjs/ts/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// #docplaster
// #docregion
import { Component, OnInit } from '@angular/core';
import { EventAggregatorService } from './event-aggregator.service';
import { ObservablePrinciples } from './observable-principles';

@Component({
selector: 'my-app',
template: `
<h1 class="title">RxJS in Angular</h1>

<a routerLink="/hero/add">Add Hero</a><br>
<a routerLink="/heroes">Heroes</a><br>
<a routerLink="/hero/counter">Hero Counter</a><br>

<router-outlet></router-outlet>

<loading-component></loading-component>
<message-log></message-log>
`
})
export class AppComponent implements OnInit {
constructor(
private eventService: EventAggregatorService,
private principles: ObservablePrinciples) {}

ngOnInit() {
this.eventService.add({
type: 'init',
message: 'Application Initialized'
});

this.principles.callFunctionalExamples();
this.principles.callPromiseExamples();
}
}
53 changes: 53 additions & 0 deletions public/docs/_examples/rxjs/ts/src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// #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 { HeroListComponent } from './hero-list.component';
import { HeroCounterComponent } from './hero-counter.component';
import { MessageLogComponent } from './message-log.component';
import { LoadingComponent } from './loading.component';
import { AddHeroComponent } from './add-hero.component';

import { ObservablePrinciples } from './observable-principles';
import { LoadingService } from './loading.service';
import { HeroService } from './hero.service';

// #docregion event-aggregator-import
import { EventAggregatorService } from './event-aggregator.service';
// #enddocregion event-aggregator-import

// Imports for loading & configuring the in-memory web api
import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
import { InMemoryDataService } from './in-memory-data.service';

@NgModule({
imports: [
BrowserModule,
HttpModule,
AppRoutingModule,
ReactiveFormsModule,
InMemoryWebApiModule.forRoot(InMemoryDataService)
],
declarations: [
AppComponent,
HeroCounterComponent,
HeroListComponent,
MessageLogComponent,
LoadingComponent,
AddHeroComponent
],
providers: [
ObservablePrinciples,
HeroService,
LoadingService,
EventAggregatorService
],
bootstrap: [ AppComponent ]
})
export class AppModule {
}
// #enddocregion
25 changes: 25 additions & 0 deletions public/docs/_examples/rxjs/ts/src/app/event-aggregator.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// #docplaster
// #docregion
// #docregion imports
import 'rxjs/add/operator/scan';
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
// #enddocregion imports

// #docregion event-interface
export interface AppEvent {
type: string;
message: string;
}
// #enddocregion event-interface

@Injectable()
export class EventAggregatorService {
_events$: BehaviorSubject<AppEvent[]> = new BehaviorSubject<AppEvent[]>([]);
events$ = this._events$
.scan((events, event) => events.concat(event), []);

add(event: AppEvent) {
this._events$.next([event]);
}
}
Loading