unexpected transition happened with router change after calling applicationRef.attachView
See original GitHub issueπ bug report
Affected Package
@angular/animations
@angular/router
Is this a regression?
no
Description
The unexpected transition will happen when router change after attaching the component with the applicationRef.attachView
π¬ Minimal Reproduction
Angular 8.x: https://stackblitz.com/edit/angular-router-transition-bug?file=src/app/app.component.ts Angular 9.0.0-rc.8: https://stackblitz.com/edit/github-va6d8q?file=src/app/app.component.ts
- click the router link, you would find the unexpected transition happened
- comment this line
this.applicationRef.attachView(view.hostView); - click the router link again, you would find the transition wonβt happen anymore.
remove the BrowserAnimationsModule could also stop the transition bug, so maybe the BrowserAnimationsModule cause the root issue.
π₯ Exception or Error
the unexpected transition happened when router change

π Your Environment
Angular Version:
The bug still exists in the latest angular version 9.0.0-rc.8, It breaks all transition style in our components after any overlay created with @angular/cdk
@angular-devkit/architect 0.803.21
@angular-devkit/build-angular 0.803.21
@angular-devkit/build-optimizer 0.803.21
@angular-devkit/build-webpack 0.803.21
@angular-devkit/core 8.3.21
@angular-devkit/schematics 8.3.21
@angular/cdk 8.2.3
@angular/cli 8.3.21
@ngtools/webpack 8.3.21
@schematics/angular 8.3.21
@schematics/update 0.803.21
rxjs 6.4.0
typescript 3.5.3
webpack 4.39.2
Anything else relevant?
I have debugged this issue with DOM breakpoint and find that the className was added in different sequence if there is an attached view, which caused this issue.
-
the transition className was added immediately after router change if there is no attached view, this is the expected behavior.

-
the transition className was not added after router change if there is an attached view, and the className was added in the next tick, which caused the unexpected transition. this is not the expected behavior.

Here is one ng-zorro-antd bug caused by this issue
Hope it could be fixed before angular 9 release ref @angular/cdk
Issue Analytics
- State:
- Created 4 years ago
- Reactions:12
- Comments:11 (11 by maintainers)

Top Related StackOverflow Question
Hi @pkozlowski-opensource Would this issue be fixed in the 9.1.0 version? Our component libs depend on the angular animation heavily, we implement a hack directive to skip this issue, but still hopes angular could fix this issue soon https://github.com/NG-ZORRO/ng-zorro-antd/blob/af4051eb11a5c9a571d7ccdea75774ea786ba990/components/core/transition-patch/transition-patch.directive.ts#L18
TL;DR - Jump to the bottom of this comment for possible solutions.
Thereβs still a fair amount I donβt know, but hereβs what I understand so far:
markForCheckrouter. Meaning that the component is created but change detection has not run yet (dynamic host bindings are assigned during change detection, not during element creation)AppComponent, it gets added to theApplicationRefβs_viewsbeforeAppComponent. This is significant because that means when change detection runs, it will be processed first when change detection runs. After each root view component, the animation engine flushes. See https://github.com/angular/angular/blob/90c0772743fda18e6b4bab6feaa731038b872cbc/packages/core/src/render3/instructions/shared.ts#L1876-L1880 -> https://github.com/angular/angular/blob/90c0772743fda18e6b4bab6feaa731038b872cbc/packages/core/src/render3/instructions/shared.ts#L492 -> https://github.com/angular/angular/blob/90c0772743fda18e6b4bab6feaa731038b872cbc/packages/platform-browser/animations/src/animation_renderer.ts#L122. I think this flush results in the adding of the component happening in a βseparate tickβ from the hostbinding class being added (again, similar to the first bullet point)attachViewcall. There are other things that might cause the browser to βseeβ the addition of the class with the transition as a separate operation (again, see the first bullet point)There are a couple possible solutions for you:
'[class.X]': "true". So converthost: {"[class.transition]": "true"}tohost: {"class": "transition"}.applicationRef.attachViewin thengOnInitofApplicationRef. This will mean that the root view with the router outlet is processed firstRouterOutletto pass toparentContexts.onChildOutletCreated): Forkrouter-outletand inactivateWith, callthis.changeDetector.detectChanges();instead of or right beforethis.changeDetector.markForCheck();. This will cause the change detection to run for your created component immediately and the host binding should be applied before the browser can βseeβ that the class wasnβt there at the start.Given that there are several possible solutions here, Iβm setting the priority lower. I donβt think thereβs much that can be done in the core package to fix this. Dynamic bindings have to be processed later because they could depend on component data that in turn depends on change detection running. This could be addressed in the
router-outletby callingdetectChangesinactivateWithlike option #3, but Iβm wary of making this change because it might cause other unexpected failures (changing the behavior of CD in the core components is quite often a breaking change).