'Production build in Angular is having intermittent change detection issues

I'm running into an internmittent issue in Angular that happens in production build only. It seems like the component does't detect changes correctlly, examples are when I route to different component, both components (before routing, and after routing) show side by side... Another case when I render a component insidie cdk portal, the component doesn't render... Here is why I'm thinking it is change detection issue, if I right click on the page or I press F12 for example the component renders as expected. There are no errors any where. And this has never happened in dev build, only in production build.

There is no specific code that I can share to demonstrate the issue, I'm asking to see if anyone has any idea what could be the root cause and if they have encountered an issue like that before?

Currently using Angular V11.2.3 and the code base is big



Solution 1:[1]

After more digging, I'm very convinced this is change detection issue happening in production build only. I can't pin-point why only production build, my assumption is Angular takes more conservative approach in detecting changes in production versus in dev build.

I was able to mitigate the issue by manually triggering change detection on the component initiating the routing...

this.router.navigate([route]);
setTimeout(() => {
    this.cdr.markForCheck();
    this.cdr.detectChanges();
}, 50);

}

I don't know if it is better with or without setTimeout, I added it to release the UI thread for other changes to happen then triggering the change detection

As for creating component inside portat, after attaching the component I'm triggering change detection, something like below

const componentPortal = new ComponentPortal(MyComponent, null, injectionTokens);
const componentRef = overlayRef.attach(componentPortal);
componentRef.changeDetectorRef.markForCheck();
componentRef.changeDetectorRef.detectChanges();

I hope this shed some light for anyone facing similar issue


Update

The above code was adhoc fix per situation, obviously not feasible solution nor it was addressing the root cause. I found out while the component was rendering with above code, all children of the component were not detecting any changes (unless manually triggered) it was also like the component change detection tree was detached from Angular.

After a lot of reading and diving deep into how Angular detect changes, I cam across NgZone (read about it, it is very interesting). Angular monkey-patch each asynchronous event, so whenever any event occurs Angular runs change detection over its component tree. In my case I was using SignalR where backend send async events to the frontend, apparently Angular have not patched those events hence not detecting any change triggered by it (or to be more precise, sometimes not detecting those changes and going into a weird state of not detecting changes). For anyone reading this, look at all async functions you have including all libraries using async functions and do below.

Now for solution, in my case I was using SignalR. Running functions inside NgZone made Angular aware of the async events and handled change detection gracefully

constructor(
    private _zone: NgZone
) { }

this.connection$.on("AsyncEvent", (data: any) => {
    // Notice we are handling the event inside NgZone
    this._zone.run(() => {
        this.processEvent(data);
    });
});

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 marc_s