Last active
March 24, 2017 19:08
-
-
Save jrgcubano/8e557590844a73a853668c17ddebdf44 to your computer and use it in GitHub Desktop.
ReactiveExtensions Angular 2 examples for http calls (cached, delay, recursive)
This file contains hidden or 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
<h1>{{title}}</h1> | |
<div *ngFor="let user of usersA"> | |
{{user.name.first}} | |
</div> | |
<button (click)="loadSubscriptionA()">Load A</button> | |
<button (click)="unloadSubscriptionA()">Unload A</button> | |
<div *ngFor="let user of usersB"> | |
{{user.name.first}} | |
</div> | |
<button (click)="loadSubscriptionB()">Load B</button> | |
<button (click)="unloadSubscriptionB()">Unload B</button> | |
<div *ngFor="let user of usersC"> | |
{{user.name.first}} | |
</div> | |
<button (click)="loadSubscriptionC()">Load C</button> | |
<button (click)="unloadSubscriptionC()">Unload C</button> | |
This file contains hidden or 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
import { Component } from '@angular/core'; | |
import { UsersService } from '../shared/services/index'; | |
@Component({ | |
selector: 'app-root', | |
templateUrl: './app.component.html', | |
styleUrls: ['./app.component.css'] | |
}) | |
export class AppComponent { | |
usersA = []; | |
usersB = []; | |
usersC = []; | |
subscriptionA; | |
subscriptionB; | |
subscriptionC; | |
title; | |
constructor(private _usersService:UsersService) {} | |
loadSubscriptionA() { | |
this.subscriptionA = | |
this._usersService.getUsers() | |
.subscribe( | |
res => { | |
if(!res.isError) { | |
console.log("Data A: " + res.data) | |
this.usersA = res.data; | |
} else { | |
console.log("Error by result A: " + res.data) | |
} | |
}, | |
err => console.log("Error By Throw A: " + err)); | |
} | |
unloadSubscriptionA() { | |
this.subscriptionA.unsubscribe(); | |
this.usersA = null; | |
} | |
loadSubscriptionB() { | |
this.subscriptionB = | |
this._usersService.getUsers() | |
.subscribe( | |
res => { | |
if(!res.isError) { | |
console.log("Data B: " + res.data) | |
this.usersB = res.data; | |
} else { | |
console.log("Error by result B: " + res.data) | |
} | |
}, | |
err => console.log("Error By Throw B: " + err)); | |
} | |
unloadSubscriptionB() { | |
this.subscriptionB.unsubscribe(); | |
this.usersB = null; | |
} | |
loadSubscriptionC() { | |
this.subscriptionC = | |
this._usersService.getUsers() | |
.subscribe( | |
res => { | |
if(!res.isError) { | |
console.log("Data C: " + res.data) | |
this.usersC = res.data; | |
} else { | |
console.log("Error by result C: " + res.data) | |
} | |
}, | |
err => console.log("Error By Throw C: " + err)); | |
} | |
unloadSubscriptionC() { | |
this.subscriptionC.unsubscribe(); | |
this.usersC = null; | |
} | |
ngOnInit(){ | |
this.title = 'app works!!!'; | |
console.log("Hola!!"); | |
// this.loadSubscriptionA(); | |
// this.loadSubscriptionB(); | |
// this.loadSubscriptionC(); | |
} | |
ngOnDestroy(){ | |
this.unloadSubscriptionA(); | |
this.unloadSubscriptionB(); | |
this.unloadSubscriptionC(); | |
console.log('Destroyed'); | |
} | |
} |
This file contains hidden or 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
import { BrowserModule } from '@angular/platform-browser'; | |
import { NgModule } from '@angular/core'; | |
import { FormsModule } from '@angular/forms'; | |
import { HttpModule } from '@angular/http'; | |
import { AppComponent } from './app.component'; | |
import { UsersService } from '../shared/services/index'; | |
@NgModule({ | |
imports: [ BrowserModule, FormsModule, HttpModule ], | |
declarations: [ AppComponent ], | |
providers: [ UsersService ], | |
bootstrap: [AppComponent] | |
}) | |
export class AppModule { } |
This file contains hidden or 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
<!doctype html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>RxServiceCache</title> | |
<base href="/"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<link rel="icon" type="image/x-icon" href="favicon.ico"> | |
</head> | |
<body> | |
<app-root>Loading...</app-root> | |
</body> | |
</html> |
This file contains hidden or 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
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; | |
import { enableProdMode } from '@angular/core'; | |
import { environment } from './environments/environment'; | |
import { AppModule } from './app/app.module'; | |
import 'rxjs/add/operator/map'; | |
import 'rxjs/add/operator/expand'; | |
import 'rxjs/add/operator/switchMap'; | |
import 'rxjs/add/observable/of'; | |
// import 'rxjs/add/operator/debounceTime'; | |
// import 'rxjs/add/operator/distinctUntilChanged'; | |
// import 'rxjs/add/operator/publishReplay'; | |
import 'rxjs/Rx'; | |
if (environment.production) { | |
enableProdMode(); | |
} | |
platformBrowserDynamic().bootstrapModule(AppModule); |
This file contains hidden or 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
import { Injectable } from '@angular/core'; | |
import { Http, Response} from '@angular/http'; | |
import { Observable } from 'rxjs/Rx'; | |
import 'rxjs/add/operator/expand'; | |
@Injectable() | |
export class UsersService { | |
_users:Observable<any> = null; | |
constructor(private _http: Http) { | |
} | |
clearCache(){ | |
this._users = null; | |
} | |
// Recursive iteration to get data with delay (not cached) | |
// getApiData() { | |
// return this._http.get('https://randomuser.me/api/?page=1&results=10') | |
// .map((res:Response) => res.json().results) | |
// .timestamp() | |
// .do(i => console.log(`[debug] Data retreived from server @${i.timestamp}`)); | |
// } | |
// getUsers() { | |
// if(!this._users){ | |
// this._users = | |
// this.getApiData() | |
// .expand(_ => Observable.of([]) | |
// .delay(5000) | |
// .timestamp() | |
// .do(i => console.log(`[debug] Waiting 5sec for next getData ${i.timestamp}`)) | |
// .concatMap(() => this.getApiData()) | |
// ); | |
// } | |
// return this._users; | |
// } | |
// Cached only with retention delay | |
// getApiData() { | |
// return this._http.get('https://randomuser.me/api/?page=1&results=10') | |
// .map((res:Response) => res.json().results) | |
// // .timestamp() | |
// // .do(i => console.log(`[debug] Data retreived from server @${i.timestamp}`)) | |
// .catch(err => Observable.of(err)); | |
// } | |
// getUsers() { | |
// if(!this._users){ | |
// this._users = | |
// Observable.defer(() => this.getApiData()) | |
// // .timestamp() | |
// // .do(i => console.log(`[debug] Waiting 5sec for next getData ${i.timestamp}`)) | |
// .publishReplay(1, 3000) | |
// .refCount() | |
// .take(1); | |
// } | |
// return this._users; | |
// } | |
// Recursive iteration with delay and cached retention delay | |
// getApiData() { | |
// return this._http.get('https://randomuser.me/api/?page=1&results=10') | |
// .map((res:Response) => res.json().results) | |
// .timestamp() | |
// .do(i => console.log(`[debug] Data retreived from server @${i.timestamp}`)); | |
// } | |
// getUsers() { | |
// if(!this._users){ | |
// this._users = | |
// Observable.of([]) | |
// .mergeMap(i => | |
// this.getApiData() | |
// .expand(_ => Observable.of([]) | |
// .delay(5000) | |
// .timestamp() | |
// .do(i => console.log(`[debug] Waiting 5sec for next getData ${i.timestamp}`)) | |
// .concatMap(() => this.getApiData()) | |
// ) | |
// ) | |
// .publishReplay(1, 5000) | |
// .refCount(); | |
// //.take(1); | |
// } | |
// return this._users; | |
// Recursive iteration with delay and cached retention delay (clean version without "do" and "timestamp" logs!!!) | |
getApiData() { | |
return this._http.get('https://randomuser.me/api/?page=1&results=10') | |
.map((res:Response) => new UsersResult(res.json().results, false)) | |
// (3) Error strategy: Pass errors as result on the same observable | |
// and retain subscriptions with the same delay until connection back | |
.catch((error:any) => | |
Observable.of(new UsersResult((error.json().error || 'Server error'), true)) | |
);; | |
} | |
getUsers() { | |
if(!this._users){ | |
this._users = | |
Observable.of([]) | |
.mergeMap(i => this.getApiData() | |
.expand(_ => | |
Observable.of([]) | |
.delay(5000) | |
.concatMap(() => this.getApiData()) | |
) | |
) | |
.publishReplay(1, 5000) | |
.refCount() | |
// (1) Error strategy: Just throw and break subscriptions for all consumers | |
// .catch((error:any) => { | |
// this._users = null; | |
// return Observable.throw(error.json().error || 'Server error') | |
// }); | |
// (2) Error strategy: Pass errors as result on the same observable and stop subscriptions | |
//.catch((error:any) => | |
// Observable.of(new UsersResult((error.json().error || 'Server error'), true)) | |
//); | |
} | |
return this._users; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
TODO: Testing with https://blog.hyphe.me/rxjs-testing-in-real-world-applications/ (using spies or net approach injecting scheduler on all services to control time!).