Angular 7: ChangeDetectorRef detectChanges() causes infinite loop when called from inside a subscription
Asked Answered
H

1

1

I am posting here after reading all the material related to change detection and similar post and failing to solve my problem.

ChangeDetectorRef detectChanges() causes infinite loop when called from inside a subscription. If I don't call detectChanges, I get ExpressionChangedAfterCheck error. I seriously don't know how to solve, and why is the ExpressionChangedAfterCheck error comes

ngAfterViewInit() {
    this.route.params.subscribe((params) => {
      this.userId = params.userId;
      if (this.userId != undefined) {
        this.loadActivity();
      }
      else {
        alert("Userid not supplied");
      }
      this.cdRef.detectChanges();
    });
  }

  loadActivity() {
    while(this.layers.length > 0){
      this.layers.pop();
    }
    this.loading = true;
    this.userService.authenticatedGet(ApiUrls.GetLocation(this.userId, this.activity.from.getTime(), this.activity.to.getTime()), {}).subscribe(
      (res:any) => {
        this.user = res.user;
        this.loading = false;
        // other logic
        this.cdRef.detectChanges();
        console.log("Loading is " + this.loading);
      }
    );
  }

Note: This problem is there only when the value is bound with ngIf.

Horseweed answered 25/11, 2018 at 12:39 Comment(10)
if you remove one of this.cdRef.detectChanges(); do you get ExpressionChangedAfterCheck error ?Babin
@ArtyomAmiryan yes dear even when I wrap the call in setTimeOut I get this frustrating error. First time in life I am thinking of Angular alternative. After every new version, we get new quirks.Horseweed
for first it is wrong to have subscription inside a loop, in your while loop imagine how many times you are subscribing to your Observable, what's the purpose in every iteration update values of properties user and loading inside subscription ?Babin
See again it’s one liner while loop for clearing old dataHorseweed
Try markForCheck instead of detectChanges.Christinachristine
@GünterZöchbauer Now I am getting ExpressionChangedAfterItHasBeenChecked errorHorseweed
zone.run is another way to fix this exception #36919899Christinachristine
@GünterZöchbauer again failed :(Horseweed
Out of ideas. .Christinachristine
@GünterZöchbauer Do check the edit onesHorseweed
H
1

I resolved this. Issue was not with the lifecycle but with a directive leaflet from ngx-leaflet project.

When I removed leaflet related directive and bindings all errors vanished.

Error came even with this as well:

<ng-container *ngIf="!loading">
    <div
      class="map"
      leaflet
      (leafletMapReady)="onMapReady($event)"
      [leafletOptions]="options"
      [leafletLayers]="layers"
      [leafletLayersControl]="layersControl">
    </div>
</ng-container>

I tried adding detectChanges and markForCheck alternatively, but again got no luck.

  onMapReady(map: Map) {
    this.map = map;
    setTimeout(() => map.invalidateSize(), 1000);
    this.route.params.subscribe(params => {
      this.userId = params["userId"];
      this.loadActivity();
    });
    this.cdRef.markForCheck();
  }

Finally, I ditched leaflet while writing this answer, and I am going to try Angular-Google-Maps.

And yeah A-G-M is working fine.

Horseweed answered 26/11, 2018 at 15:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.