Search code examples
angularopenlayers

Angular ExpressionChangedAfterItHasBeenCheckedError on Input. OpenLayers Map


My MapComponent uses ControlButtonsComponent in the html and binds the Map from openlayers with @Input into the ControlButtons. This gives me the error:

core.js:5980 ERROR Error: NG0100: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'undefined'. Current value: '[object Object]'.
at throwErrorIfNoChangesMode (core.js:6549)
at bindingUpdated (core.js:12660)
at Module.ɵɵproperty (core.js:14475)
at MapComponent_Template (map.component.html:2)
at executeTemplate (core.js:9323)
at refreshView (core.js:9192)
at refreshComponent (core.js:10358)
at refreshChildComponents (core.js:8989)
at refreshView (core.js:9242)
at refreshComponent (core.js:10358)

even thought I have a ngIf="Map" in the selector

this is the html in MapComponent:

<app-control-buttons *ngIf="Map" [Map]="Map"></app-control-buttons>

an important element in this is probably how Map gets initialized in the MapComponent (taken from https://medium.com/runic-software/a-simple-guide-to-openlayers-in-angular-b10f6feb3df1):

    ngAfterViewInit(): void {
        if (!this.Map) {
            this.zone.runOutsideAngular(() => this.initMap());
        }
        setTimeout(() => this.mapReady.emit(this.Map));
    }

this is the ControlButtonsComponent:

import { Component, Input, OnInit } from '@angular/core';
import { Map} from 'ol';

@Component({
    selector: 'app-control-buttons',
    templateUrl: './control-buttons.component.html',
    styleUrls: ['./control-buttons.component.less'],
})
export class ControlButtonsComponent implements OnInit {
    @Input() Map!: Map;
    constructor() {}

    ngOnInit(): void {}
}

Solution

  • ahh I've found a solution:

    change the previous ngAfterViewInit() to this (i didnt really use the emit for anything). I created a mapReady variable that gets set true when map is ready:

        ngAfterViewInit(): void {
        if (!this.Map) {
            this.zone.runOutsideAngular(() => this.initMap());
        }
        setTimeout(() => {
            this.mapReady = true
        });
    }
    

    and check for mapReady variable in the html:

    <app-control-buttons *ngIf="mapReady" [Map]="Map"></app-control-buttons>