Search code examples
angularangular6angular2-changedetection

Angular 6 UI not updated


I've got 3 components:

c1 contains c2 and c3

c2 contains a checkbox. When checkbox is toggled I fire an event to an Output variable.

<input type="checkbox" [checked]="displayAxialMap" (click)="onToggleAxialMap()" />

and in component:

onToggleAxialMap() {
    this.displayAxialMap = !this.displayAxialMap;
    this.toggleMap.emit(<Map>{ display: this.displayAxialMap, mapType: MapType.AXIALMAP, loading: true });
}

in c1 I've got a behaviourSubject called displayMap

<c2 (toggleMap)="displayMap.next($event)"></c2>

in c1 I also pass displayMap value to c3

<c3 [displayMap]="displayMap"></c3>

c3 in ngOnInit() I do this:

this.displayMap.subscribe(map => {
   this.loading = map.loading;
   this.drawAxialMapCanvas();
   this.loading = false;
}) 

this.loading is initialized to false.

Everything is working (so there is no problem in passing data trough components). But this.drawAxialMapCanvas(); is a function that take long time to complete (3-4 seconds) and I see two strage behaviours:

  1. the checkbox in c2 change to checked only when this.drawAxialMapCanvas() completes.
  2. the local variable "loading" inside c3 (If I debug code) correcly pass from false, to true to false again. But if I put that variable in the template:

<... *ngIf"loading">Loading...

It never shows up... It takes only the last value!

It seems that my UI is updated only when this.drawAxialMapCanvas() is completed. What am I do wrong?


Solution

  • For the 1) it's normal, javascript is single thread so everything is simply blocked by this.drawAxialMapCanvas

    2) You try to show a loading message but you have here the same probleme, angular is not updating since the the.drawAxialMap is not finish and block the thread (4 secondes is really long for a non asynchrone loading).

    You can first the make the this.drawAxialMap running in the next event loop by doing :

    this.displayMap.subscribe(map => {
       this.loading = map.loading;
       setTimeout( () => {
        this.drawAxialMapCanvas();
        this.loading = false;
       )};
    });
    

    It will let the time to refresh (checkbox, message..)

    Anyway you should do something about this.drawAxialMapCanvas(); I never have faced this situation but perhaps use a worker or loading part by part by using something like [ setTimeout() / setImmediate()] to let the UI the time to manage user event etc...