From 353362f5a4ce14e91cc96359a990013f10747b47 Mon Sep 17 00:00:00 2001 From: cexbrayat Date: Sun, 13 Jan 2019 14:38:56 +0100 Subject: [PATCH] docs(core): document isStable traps (#28102) PR Close #28102 --- packages/core/src/application_ref.ts | 90 ++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/packages/core/src/application_ref.ts b/packages/core/src/application_ref.ts index 22acad53c1..8669e889fc 100644 --- a/packages/core/src/application_ref.ts +++ b/packages/core/src/application_ref.ts @@ -359,6 +359,94 @@ function optionsReducer(dst: any, objs: T | T[]): T { /** * A reference to an Angular application running on a page. * + * @usageNotes + * + * {@a is-stable-examples} + * ### isStable examples and caveats + * + * Note two important points about `isStable`, demonstrated in the examples below: + * - the application will never be stable if you start any kind + * of recurrent asynchronous task when the application starts + * (for example for a polling process, started with a `setInterval`, a `setTimeout` + * or using RxJS operators like `interval`); + * - the `isStable` Observable runs outside of the Angular zone. + * + * Let's imagine that you start a recurrent task + * (here incrementing a counter, using RxJS `interval`), + * and at the same time subscribe to `isStable`. + * + * ``` + * constructor(appRef: ApplicationRef) { + * appRef.isStable.pipe( + * filter(stable => stable) + * ).subscribe(() => console.log('App is stable now'); + * interval(1000).subscribe(counter => console.log(counter)); + * } + * ``` + * In this example, `isStable` will never emit `true`, + * and the trace "App is stable now" will never get logged. + * + * If you want to execute something when the app is stable, + * you have to wait for the application to be stable + * before starting your polling process. + * + * ``` + * constructor(appRef: ApplicationRef) { + * appRef.isStable.pipe( + * first(stable => stable), + * tap(stable => console.log('App is stable now')), + * switchMap(() => interval(1000)) + * ).subscribe(counter => console.log(counter)); + * } + * ``` + * In this example, the trace "App is stable now" will be logged + * and then the counter starts incrementing every second. + * + * Note also that this Observable runs outside of the Angular zone, + * which means that the code in the subscription + * to this Observable will not trigger the change detection. + * + * Let's imagine that instead of logging the counter value, + * you update a field of your component + * and display it in its template. + * + * ``` + * constructor(appRef: ApplicationRef) { + * appRef.isStable.pipe( + * first(stable => stable), + * switchMap(() => interval(1000)) + * ).subscribe(counter => this.value = counter); + * } + * ``` + * As the `isStable` Observable runs outside the zone, + * the `value` field will be updated properly, + * but the template will not be refreshed! + * + * You'll have to manually trigger the change detection to update the template. + * + * ``` + * constructor(appRef: ApplicationRef, cd: ChangeDetectorRef) { + * appRef.isStable.pipe( + * first(stable => stable), + * switchMap(() => interval(1000)) + * ).subscribe(counter => { + * this.value = counter; + * cd.detectChanges(); + * }); + * } + * ``` + * + * Or make the subscription callback run inside the zone. + * + * ``` + * constructor(appRef: ApplicationRef, zone: NgZone) { + * appRef.isStable.pipe( + * first(stable => stable), + * switchMap(() => interval(1000)) + * ).subscribe(counter => zone.run(() => this.value = counter)); + * } + * ``` + * * @publicApi */ @Injectable() @@ -384,6 +472,8 @@ export class ApplicationRef { /** * Returns an Observable that indicates when the application is stable or unstable. + * + * @see [Usage notes](#is-stable-examples) for examples and caveats when using this API. */ // TODO(issue/24571): remove '!'. public readonly isStable !: Observable;