Search code examples
javascriptangularscopearrow-functionsangular2-changedetection

Why is Angular's ChangeDetection not triggered when using canvas.toBlob() with an arrow function?


I have a very simple component in Angular 10. When a form is submitted the Blob of an canvas-element is created and stored.

Therefor the releveant part of the onSubmit() function looks like this:

onSubmit(): void {
  const canvas: HTMLCanvasElement = getCanvas();

  canvas.toBlob((blob: Blob) => {
    this.service.create(blob).pipe(first()).subscribe((response: boolean) => {
      this.isSuccessful = response;
    });
  }, 'image/png', 1);
}

The problem is, that isSuccessful is changed, but these changes are not reflected in the template.

So what I did is to manually trigger change detection, using a ChangeDetectorRef:

onSubmit(): void {
  const canvas: HTMLCanvasElement = getCanvas();

  canvas.toBlob((blob: Blob) => {
    this.service.create(blob).pipe(first()).subscribe((response: boolean) => {
      this.isSuccessful = response;
      this.cdr.detectChanges();
    });
  }, 'image/png', 1);
}

Now, this works. But why is it needed here? In all other cases, when I used an arrow function like this, no change detector was necessary. The toBlob() method seems to be different that way.

PS: The cdr is also not needed, when the service.create() method is outside the toBlob()method.


Solution

  • Change detection is not triggered because canvas.toBlob executes the callback outside of the Angular Zone. An alternative to calling ChangeDetectorRef.detectChanges is to make sure that the code is executed inside the Angular zone with NgZone.run:

    import { NgZone } from '@angular/core';
    ...
    
    constructor(private ngZone: NgZone) { }
    
    canvas.toBlob((blob: Blob) => {
      this.ngZone.run(() => {
        // Run the code here
      });
    }, 'image/png', 1);
    

    See this stackblitz for a demo.