Angular Binding Not Changing Before Observable Call

时间:2018-04-18 18:02:33

标签: javascript angular rxjs observable

I'm using Angular 4+, and I noticed Angular is not updating the binded value before I call Observable.subscribe() when the Observable resolves immediately (synchronously?). In other places this works fine, because a network call delays the Observable completion long enough for the initial binding change to take effect in Angular.

https://plnkr.co/edit/LV0On7?p=preview

//our root app component
import {Component, VERSION} from '@angular/core';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/delay';

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>{{name}}</h2>
      <button class="btn btn-primary" (click)="onAlertClickedNoDelay()">Call Observable Without Delay</button>
      <button class="btn btn-primary" (click)="onAlertClickedDelay()">Call Observable With Delay</button>

      <alert *ngIf="isAlertVisible()" type="success" dismissible="true" (onClose)="onAlertClose()">
          Async action successful!
      </alert>
    </div>
  `,
})
export class AppComponent {
  name:string;
  private isCallComplete = false;
  isAlertVisible(): boolean {
    console.log("isAlertVisible() binding updating: ", this.isCallComplete);
    return this.isCallComplete;
  }
  constructor() {
    this.name = `Angular! v${VERSION.full}`
  }

   onAlertClickedNoDelay() {
    this.isCallComplete = false;
    console.log("set isCallComplete = false");
    Observable.of("some data").subscribe(data => {
      this.isCallComplete = true;
      console.log("set isCallComplete = true");
    });
  }

   onAlertClickedDelay() {
    this.isCallComplete = false;
    console.log("set isCallComplete = false");
    Observable.of("some data").delay(0).subscribe(data => {
      this.isCallComplete = true;
      console.log("set isCallComplete = true");
    });
  }

  onAlertClose() {
    this.isCallComplete = false;
    console.log("set isCallComplete = false");
  }
}

Without Observable.delay(), console prints:

set isCallComplete = false
set isCallComplete = true
isAlertVisible() binding updating: true
isAlertVisible() binding updating: true

When using Observable.delay(), console correctly prints:

set isCallComplete = false
isAlertVisible() binding updating: false
isAlertVisible() binding updating: false
set isCallComplete = true
isAlertVisible() binding updating: true
isAlertVisible() binding updating: true

1) Why does Angular detect the initial property binding (isCallComplete = false) when using Observable.delay(0).subscribe() and not Observable.subscribe()?

2) What is the best solution to bind to a busy property value before a Observable.subscribe() call?

1 个答案:

答案 0 :(得分:2)

Because Angular never gets the chance to check the value of isCallComplete.

Your Observable's subscribe callback gets executed right after it is created.

Using delay(0) would be the equivalent of using setTimeout(()=>/*...*/,0), thus delaying the execution of the subscribe callback after the current synchronous code has executed (in this case Angular checking your component's values)