ExpressionChangedAfterItHasBeenCheckedError Explained

前端 未结 26 1518
慢半拍i
慢半拍i 2020-11-22 14:46

Please explain to me why I keep getting this error: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked.

Obviously,

26条回答
  •  伪装坚强ぢ
    2020-11-22 15:31

    @HostBinding can be a confusing source of this error.

    For example, lets say you have the following host binding in a component

    // image-carousel.component.ts
    @HostBinding('style.background') 
    style_groupBG: string;
    

    For simplicity, lets say this property is updated via the following input property:

    @Input('carouselConfig')
    public set carouselConfig(carouselConfig: string) 
    {
        this.style_groupBG = carouselConfig.bgColor;   
    }
    

    In the parent component you are programatically setting it in ngAfterViewInit

    @ViewChild(ImageCarousel) carousel: ImageCarousel;
    
    ngAfterViewInit()
    {
        this.carousel.carouselConfig = { bgColor: 'red' };
    }
    

    Here's what happens :

    • Your parent component is created
    • The ImageCarousel component is created, and assigned to carousel (via ViewChild)
    • We can't access carousel until ngAfterViewInit() (it will be null)
    • We assign the configuration, which sets style_groupBG = 'red'
    • This in turn sets background: red on the host ImageCarousel component
    • This component is 'owned' by your parent component, so when it checks for changes it finds a change on carousel.style.background and isn't clever enough to know that this isn't a problem so it throws the exception.

    One solution is to introduce another wrapper div insider ImageCarousel and set the background color on that, but then you don't get some of the benefits of using HostBinding (such as allowing the parent to control the full bounds of the object).

    The better solution, in the parent component is to add detectChanges() after setting the config.

    ngAfterViewInit()
    {
        this.carousel.carouselConfig = { ... };
        this.cdr.detectChanges();
    }
    

    This may look quite obvious set out like this, and very similar to other answers but there's a subtle difference.

    Consider the case where you don't add @HostBinding until later during development. Suddenly you get this error and it doesn't seem to make any sense.

提交回复
热议问题