Skip to content
Permalink
Browse files

docs(core): document isStable traps (#28102)

PR Close #28102
  • Loading branch information...
cexbrayat authored and matsko committed Jan 13, 2019
1 parent 0e6f799 commit 353362f5a4ce14e91cc96359a990013f10747b47
Showing with 90 additions and 0 deletions.
  1. +90 −0 packages/core/src/application_ref.ts
@@ -359,6 +359,94 @@ function optionsReducer<T extends Object>(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<boolean>;

1 comment on commit 353362f

@IgorMinar

This comment has been minimized.

Copy link
Member

IgorMinar commented on 353362f Feb 15, 2019

This is an awesome contribution! Thank you, @cexbrayat!

Please sign in to comment.
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.