Change detection not triggered on some event

2.4k views Asked by At

I have a component that subscribes to an Observable from a service. When the observable emits its next value some change happen in my component. The strange thing is that the component will or will not update the view depending on how the next value has been generated. If I understand this correctly some events have been monkey patched by angular 2 as to trigger change detection and some haven't been. MIDI event are one of those that haven't (which makes kinda sens).

If the service looks for click events in order to trigger the next value, the change is reflected in the view. Therefor the change detection happens.

If the service looks for keyboard events same thing, the change detection happens.

However, when the service use a MIDI event, no change detection happens.

Here some code :

export class App {

  arr = [
      {id: 1, status: false},
      {id: 2, status: false},
      {id: 3, status: false}
    ];

  thing = new Subject<boolean>();

  constructor(private renderer: Renderer,
              private ser:Ser,
              private midi: MidiService) {}

  ngOnInit(){
    // listening to click events, will trigger change detection
    this.renderer.listenGlobal('document', 'click', (event) => {
      console.log("Left click", event);
      this.thing.next(1);
    });
    this.thing.subscribe( v => this.toggle(v));
    // my midi service events will call the toggle method however the 
    // changes won't be displayed in the view
    this.midi.notesPayed$.subscribe(v => this.toggle(v));
  }

And here is a plnkr :

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

I'm not sure if this is a bug or a feature from the underlying workings of angular 2. In any case I would like to know why this happens. The concrete issue is easily resolvable by calling the change detection myself, so I don't need a solution.

1

There are 1 answers

2
Günter Zöchbauer On BEST ANSWER

That's known behavior. The MIDI API is not covered by zone.js and therefore Angulare doesn't get notified to run change detection.

Either inject zone:NgZone and wrap the code that changes the model with this.zone.run(() => {...})

or inject cdRef:ChangeDetectorRef and invoke change detection after the change by calling this.cdRef.detectChanges()