2

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.

lampshade
  • 2,470
  • 3
  • 36
  • 74
  • what is getCanvas() doing? can you share that? – Manuel Panizzo Sep 02 '20 at 19:23
  • @ManuelPanizzo This method creates a new `canvas`-element using `this.document.createElement('canvas')` and does some drawings on it. `this.document` was injected like this `@Inject(DOCUMENT) private document: HTMLDocument`. – lampshade Sep 03 '20 at 07:40

1 Answers1

2

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.

ConnorsFan
  • 70,558
  • 13
  • 122
  • 146
  • Ah I see. That totally makes sense. Didn't have the `Zone` in mind. Thanky you. Is there a benefit of using `ngZone.run()` over `ChangeDetectorRef.detectChanges()` in this case or ist it really only an alternative? – lampshade Sep 03 '20 at 07:56
  • 1
    You can take a look at [this post](https://stackoverflow.com/q/42971865/1009922) for a comparison between the two methods. In your case, in addition to the arguments given in Gunter's answer, I would prefer `NgZone.run` because it makes the code clear as to the reason why change detection is not called automatically. – ConnorsFan Sep 03 '20 at 16:06
  • Thanks a lot for the link and a good reason to use one over the other. – lampshade Sep 05 '20 at 13:18