Forcing change detection on third-party Angular components

Sébastien Dubois / July 17, 2020

3 min read

Here’s a way to work around change detection issues with third party Angular components.

Picture courtesy of https://unsplash.com/@35mm

In our applications, we should do our best to keep using the OnPush change detection strategy. Unfortunately, sometimes we’re stuck with third party components that don’t detect changes appropriately.

For instance, I’ve been regularly facing issues with change detection and PrimeNG components, which (at this point) still don’t use the OnPush strategy.

Of course, change detection issues are often caused by bug lurking around, but we don’t always have the luxury to wait for fixes.

In this article I’ll share a tip given by Anthony Miller to force change detection on any component; whether it’s yours or a third party one.

Forcing change detection

As you probably know, in Angular applications, we can force change detection using the ChangeDetectorRef, which we can simply inject in our components.

The ChangeDetectorRef has multiple methods such as markForCheck and detectChanges which can do what we want.

As I’ve explained in my book, there’s a change detector tree parallel to the component tree, so each component actually has its own change detector attached.

The thing is that, depending on which one we use, we cause more or less work. For instance, when the App component forces change detection using it’s ChangeDetectorRef, then it forces change detection on a large tree.

Obviously it is recommended to force change detection only on the specific component where you need it (ideally, nowhere, but real life happens).

So, if there’s a change detection issue with a specific component, then we in fact want to force change detection through the change detector of that specific component, so that it only triggers it for that component (and its children).

Accessing other component’s injectors

To get access to the ChangeDetectorRef instance of a component, we simply need to inject it through the constructor:

constructor(private changeDetectorRef: ChangeDetectorRef) { ... }

Once injected, we can simply use it. Of course there’s a catch: a component can only use its own injector… or so you’d think!

There’s actually a way to access another component’s injector to the ViewContainerRef of the target component:

In the example above, the CoolComponent uses the Whatever component. In order to access the change detector instance of the Whatever component, we first create a template reference variable in the template, then we make use of the ViewChild decorator to get a hold of the ViewContainerRef of that component.

Finally, in the ngAfterViewInit method of our component, we simply make use of the injector of the component, which we can access through the ViewContainerRef to retrieve the ChangeDetectorRef of the component. Neat!

Conclusion

Thanks to Anthony Miller, we now have one more tool in our kit to help us work around nasty change detection bugs without resorting to ugly hacks.

As I’ve explained in this article, we can access the injector of any component through its ViewContainerRef, and use it to retrieve its ChangeDetectorRef (or anything else by the way). That way, we can trigger change detection very precisely and avoid causing massive change detection cycles when it’s not needed.

That’s it for today!

PS: check out my Dev Concepts books, join the Software Crafters community, the Personal Knowledge Management community, and come say hi on Twitter!
Discuss on TwitterEdit on GitHub