@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.