-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ab48b8a
commit d0971e7
Showing
2 changed files
with
376 additions
and
0 deletions.
There are no files selected for viewing
213 changes: 213 additions & 0 deletions
213
...demo-rx-stateful/src/app/demos/demo-error-rx-stateful/demo-error-rx-stateful.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,213 @@ | ||
import {Component, inject} from '@angular/core'; | ||
import {CommonModule} from '@angular/common'; | ||
import {rxStateful$, withRefetchOnTrigger} from "@angular-kit/rx-stateful"; | ||
import {map, MonoTypeOperatorFunction, Observable, of, ReplaySubject, scan, share, Subject, switchMap, tap} from "rxjs"; | ||
import {HttpClient} from "@angular/common/http"; | ||
|
||
|
||
/** | ||
* Problem Scenario | ||
* Wichtig für alle Scenarien: auch 2 Sucbscriber | ||
* Ziele rxStateful mit flattening ermöglichen u. mutlicasting | ||
* | ||
* --> nach error (oder auch complete success?) kann nicht mehr angestoßen werden | ||
* action.pipe( | ||
* concatMap(() => this.blaservice.updateEinschreibung()) | ||
* ) | ||
* | ||
* UND | ||
* | ||
* methode(){ | ||
* this.blaServcice.updateEinschreibung().subscirbe(d => this.data =d) | ||
* } | ||
* | ||
* | ||
* BlaService { | ||
* updateEinschreibung(){ | ||
* return rxstateful$(this.httpCall()) | ||
* } | ||
* } | ||
* | ||
* | ||
* Als erstes: Komplette grundlagen nochmal | ||
* stream completed -Y methode und flattening operator was passiert | ||
* stream error methode und flattening was passiert | ||
*/ | ||
|
||
|
||
@Component({ | ||
selector: 'angular-kit-demo-error-rx-stateful', | ||
standalone: true, | ||
imports: [CommonModule], | ||
template: ` | ||
<div> | ||
<button (click)="id$$.next(1)">trigger</button> | ||
<button (click)="plainMethod()">plainMethod</button> | ||
<button (click)="refreshRx$.next(null)">refresh trigger rx</button> | ||
<button (click)="idRx$$.next(1)">source trigger rx</button> | ||
<div> | ||
<div>current id{{id$ | async}}</div> | ||
<div> | ||
<h2>only with refresh</h2> | ||
<ul *ngFor="let v of rxNormal$ | async"> | ||
<li>{{ v | json }}</li> | ||
</ul> | ||
</div> | ||
<hr> | ||
<div> | ||
<h2>new source trigger</h2> | ||
<ul *ngFor="let v of newPlainRx$ | async"> | ||
<li>{{ v | json }}</li> | ||
</ul> | ||
</div> | ||
</div> | ||
</div> | ||
`, | ||
styles: [], | ||
}) | ||
export class DemoErrorRxStatefulComponent { | ||
http = inject(HttpClient) | ||
action$ = new Subject<any>() | ||
|
||
id$$ = new Subject<number>() | ||
id$ = this.id$$.pipe( | ||
scan((acc, val )=> acc + val, 0) | ||
) | ||
plainMethodResult: any = null | ||
|
||
chain$ = this.id$.pipe( | ||
switchMap(id => of(Math.random()).pipe( | ||
// share({ | ||
// connector: () => new ReplaySubject(1), | ||
// resetOnRefCountZero: true, | ||
// }), | ||
// log('chain inner$') | ||
)), | ||
// log('chain$') | ||
share({ | ||
connector: () => new ReplaySubject(1), | ||
resetOnRefCountZero: true, | ||
}), | ||
tap(x => console.log('chain$ ', x)) | ||
) | ||
|
||
chainError$ = this.id$.pipe( | ||
switchMap(id => this.http.get(`https://jsonplaceholder.typicode.com/posts/${id}xx`).pipe( | ||
log('chainError$ inner') | ||
)), | ||
log('chainError$ outer') | ||
) | ||
plainhttp$ = this.http.get('https://jsonplaceholder.typicode.com/posts/1').pipe( | ||
log('plainhttp$') | ||
) | ||
|
||
plainMethod(){ | ||
this.plainhttp$.subscribe(d => | ||
this.plainMethodResult = d) | ||
this.plainhttp$.subscribe() | ||
} | ||
|
||
refreshRx$ = new Subject<any>() | ||
idRx$$ = new Subject<number>() | ||
idRx$ = this.idRx$$.pipe( | ||
scan((acc, val )=> acc + val, 0) | ||
) | ||
|
||
/*chainRx$ = this.idRx$.pipe( | ||
switchMap(id => rxStateful$(this.http.get(`https://jsonplaceholder.typicode.com/posts/${id}`)).pipe( | ||
// log('chainRx inner$') | ||
)), | ||
scan((acc, value, index) => { | ||
// @ts-ignore | ||
acc.push({ index, value }); | ||
return acc; | ||
}, []), | ||
// log('chainRx$'), | ||
share() | ||
)*/ | ||
|
||
rxNormal$ = rxStateful$(this.http.get(`https://jsonplaceholder.typicode.com/posts/1`), { | ||
refetchStrategies: [ | ||
withRefetchOnTrigger(this.refreshRx$), | ||
withRefetchOnTrigger(this.idRx$$), | ||
//withAutoRefetch(1000, 5000) | ||
], | ||
keepValueOnRefresh: true | ||
|
||
}).pipe( | ||
scan((acc, value, index) => { | ||
// @ts-ignore | ||
acc.push({ index, value }); | ||
|
||
return acc; | ||
}, []), | ||
// log('chainRx$'), | ||
) | ||
|
||
/*chainErrorRx$ = this.idRx$.pipe( | ||
switchMap(id => rxStateful$(this.http.get(`https://jsonplaceholder.typicode.com/posts/${id}xx`)).pipe( | ||
log('chainErrorRx$ inner') | ||
)), | ||
log('chainErrorRx$ outer') | ||
) | ||
plainRx$ = rxStateful$(this.http.get('https://jsonplaceholder.typicode.com/posts/1')).pipe( | ||
log('plainRx$') | ||
)*/ | ||
|
||
//newPlainRx$ = of(null) | ||
|
||
newPlainRx$ = rxStateful$( | ||
(id) => this.http.get(`https://jsonplaceholder.typicode.com/posts/${id}`), | ||
{ | ||
sourceTriggerConfig: {trigger: this.idRx$}, | ||
refetchStrategies: withRefetchOnTrigger(this.refreshRx$), | ||
}, | ||
).pipe( | ||
// log('newPlainRx$'), | ||
scan((acc, value, index) => { | ||
// @ts-ignore | ||
acc.push({ index, value }); | ||
|
||
return acc; | ||
}, []) | ||
) | ||
|
||
|
||
|
||
constructor() { | ||
//this.chainError$.subscribe() | ||
//this.chainError$.subscribe() | ||
|
||
//this.chainRx$.subscribe() | ||
//this.chainRx$.subscribe() | ||
|
||
this.newPlainRx$.subscribe() | ||
this.rxNormal$.subscribe() | ||
// | ||
// this.chain$.subscribe() | ||
// this.chain$.subscribe() | ||
} | ||
|
||
|
||
|
||
} | ||
|
||
function value$(){ | ||
return of(1).pipe( | ||
map(() => Math.random()) | ||
) | ||
} | ||
|
||
export function log<T>(label: string): MonoTypeOperatorFunction<T>{ | ||
return (source: Observable<T>) => source.pipe( | ||
tap({ | ||
next: v => console.log(`${label} [next] `, v), | ||
error: e => console.log(`${label} [error] `, e), | ||
complete: () => console.log(`${label} [complete] `), | ||
finalize: () => console.log(`${label} [finalize] `), | ||
}) | ||
) | ||
} |
163 changes: 163 additions & 0 deletions
163
apps/demo-rx-stateful/src/app/demos/demo-rx-stateful/demo-rx-stateful.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,163 @@ | ||
import {Component, inject} from '@angular/core'; | ||
import {CommonModule} from '@angular/common'; | ||
import {HttpClient} from '@angular/common/http'; | ||
|
||
import {BehaviorSubject, concatAll, delay, map, scan, Subject, switchMap, tap, toArray} from 'rxjs'; | ||
import {ActivatedRoute} from '@angular/router'; | ||
import {provideRxStatefulClient, RxStatefulClient, withConfig} from "@angular-kit/rx-stateful/experimental"; | ||
import {rxStateful$, withRefetchOnTrigger} from "@angular-kit/rx-stateful"; | ||
import {MatButtonModule} from "@angular/material/button"; | ||
|
||
@Component({ | ||
selector: 'angular-kit-demo-rx-stateful', | ||
standalone: true, | ||
imports: [CommonModule, MatButtonModule], | ||
template: ` | ||
<h1>DemoRxStatefulComponent</h1> | ||
<div> | ||
<button (click)="refresh$$.next(null)">refresh</button> | ||
</div> | ||
<div> | ||
<h4>State</h4> | ||
<div *ngIf="state$ | async as state"> | ||
<div *ngIf="state.value">{{ state.value | json }}</div> | ||
<div *ngIf="state.isSuspense">loading</div> | ||
</div> | ||
</div> | ||
<div> | ||
<h4>State Accumulated</h4> | ||
<ul *ngFor="let v of stateAccumulated$ | async"> | ||
<li>{{ v | json }}</li> | ||
</ul> | ||
</div> | ||
<!-- <div>--> | ||
<!-- <h4>Query Params</h4>--> | ||
<!-- <div>{{ query$ | async | json }}</div>--> | ||
<!-- <div>{{ value$ | async | json }}</div>--> | ||
<!-- </div>--> | ||
<!-- <br>--> | ||
<!-- <div>--> | ||
<!-- <button mat-button color="primary" (click)="page$$.next(-1)"> previous page </button>--> | ||
<!-- <button mat-button color="primary" (click)="page$$.next(1)"> next page </button>--> | ||
<!-- <button mat-button color="primary" (click)="refresh$$.next(null)"> Refresh current page </button>--> | ||
<!-- <div>--> | ||
<!-- <h4>State Accumulated</h4>--> | ||
<!-- <ul *ngFor="let v of state2Accumulated$ | async">--> | ||
<!-- <li>{{ v | json }}</li>--> | ||
<!-- </ul>--> | ||
<!-- </div>--> | ||
<!-- </div>--> | ||
`, | ||
styles: [], | ||
providers: [ | ||
provideRxStatefulClient( | ||
withConfig({ keepValueOnRefresh: false, errorMappingFn: (e) => e}) | ||
), | ||
// provideRxStatefulConfig({keepValueOnRefresh: true, errorMappingFn: (e) => e}) | ||
], | ||
}) | ||
export class DemoRxStatefulComponent { | ||
private http = inject(HttpClient); | ||
private route = inject(ActivatedRoute); | ||
refresh$$ = new Subject<any>(); | ||
|
||
client = inject(RxStatefulClient); | ||
|
||
query$ = this.route.params; | ||
|
||
value$ = this.query$.pipe(switchMap(() => this.client.request(this.fetch()).pipe( | ||
map(v => v.value) | ||
))); | ||
|
||
// instance = this.client.request(this.fetch(), { | ||
// keepValueOnRefresh: false, | ||
// keepErrorOnRefresh: false, | ||
// refreshTrigger$: this.refresh$$, | ||
// refetchStrategies: [withAutoRefetch(10000, 20000)], | ||
// }); | ||
// state$ = this.instance; | ||
// stateAccumulated$ = this.state$.pipe( | ||
// tap(console.log), | ||
// scan((acc, value, index) => { | ||
// @ts-ignore | ||
// acc.push({ index, value }); | ||
// | ||
// return acc; | ||
// }, []) | ||
// ); | ||
|
||
|
||
state$ = rxStateful$(this.fetch(400), { | ||
keepValueOnRefresh: false, | ||
keepErrorOnRefresh: false, | ||
refreshTrigger$: this.refresh$$, | ||
suspenseTimeMs: 1000, | ||
suspenseThresholdMs: 500 | ||
}); | ||
|
||
stateAccumulated$ = this.state$.pipe( | ||
tap(x => console.log({state: x})), | ||
scan((acc, value, index) => { | ||
// @ts-ignore | ||
acc.push({ index, value }); | ||
|
||
return acc; | ||
}, []) | ||
); | ||
readonly page$$ = new BehaviorSubject(0) | ||
readonly page$ = this.page$$.pipe( | ||
scan((acc, curr) => acc + curr, 0) | ||
) | ||
|
||
state2$ = rxStateful$( | ||
(page) => this.fetchPage({ | ||
page, | ||
delayInMs: 1000 | ||
}).pipe( | ||
|
||
), | ||
{ | ||
sourceTriggerConfig: { | ||
trigger: this.page$ | ||
}, | ||
refetchStrategies: withRefetchOnTrigger(this.refresh$$) | ||
} | ||
) | ||
state2Accumulated$ = this.state2$.pipe( | ||
tap(x => console.log({state: x})), | ||
scan((acc, value, index) => { | ||
// @ts-ignore | ||
acc.push({ index, value }); | ||
|
||
return acc; | ||
}, []) | ||
); | ||
|
||
fetch(delayInMs = 800) { | ||
return this.http.get<any>('https://jsonplaceholder.typicode.com/todos/1').pipe( | ||
delay(delayInMs), | ||
map((v) => v?.title), | ||
// tap(console.log) | ||
); | ||
} | ||
|
||
fetchPage(params: { | ||
delayInMs:number, | ||
page: number | ||
}) { | ||
|
||
return this.http.get<any>(`https://jsonplaceholder.typicode.com/todos?_start=${params.page * 5}&_limit=5`).pipe( | ||
delay(params.delayInMs), | ||
concatAll(), | ||
// @ts-ignore | ||
map((v) => v?.id), | ||
toArray() | ||
); | ||
} | ||
|
||
constructor() { | ||
this.state$.subscribe(); | ||
this.state$.subscribe(); | ||
} | ||
} |