From d3018c0ee71eab2ab35aff20d95e9fa882944d14 Mon Sep 17 00:00:00 2001 From: Jan Cabadaj Date: Fri, 17 Mar 2023 10:43:12 +0100 Subject: [PATCH] fix(router): fix #49457 outlet activating with old info (#49459) Avoid activating outlet with old info if route was changed before outlet activated PR Close #49459 --- .../router/src/operators/activate_routes.ts | 15 ++++--- .../test/directives/router_outlet.spec.ts | 41 +++++++++++++++++++ 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/packages/router/src/operators/activate_routes.ts b/packages/router/src/operators/activate_routes.ts index 8ac8867f405..617d49fd083 100644 --- a/packages/router/src/operators/activate_routes.ts +++ b/packages/router/src/operators/activate_routes.ts @@ -126,13 +126,16 @@ export class ActivateRoutes { this.deactivateRouteAndItsChildren(children[childOutlet], contexts); } - if (context && context.outlet) { - // Destroy the component - context.outlet.deactivate(); - // Destroy the contexts for all the outlets that were in the component - context.children.onOutletDeactivated(); + if (context) { + if (context.outlet) { + // Destroy the component + context.outlet.deactivate(); + // Destroy the contexts for all the outlets that were in the component + context.children.onOutletDeactivated(); + } // Clear the information about the attached component on the context but keep the reference to - // the outlet. + // the outlet. Clear even if outlet was not yet activated to avoid activating later with old + // info context.attachRef = null; context.route = null; } diff --git a/packages/router/test/directives/router_outlet.spec.ts b/packages/router/test/directives/router_outlet.spec.ts index 1ce815ab629..af241f094ae 100644 --- a/packages/router/test/directives/router_outlet.spec.ts +++ b/packages/router/test/directives/router_outlet.spec.ts @@ -149,6 +149,47 @@ describe('router outlet name', () => { advance(fixture); expect(fixture.nativeElement.innerHTML).toMatch('.*component 3.*component 2.*component 1'); })); + + it('should not activate if route is changed', fakeAsync(() => { + @Component({ + standalone: true, + template: '
', + imports: [RouterOutlet, CommonModule], + }) + class ParentCmp { + initDone = false; + constructor() { + setTimeout(() => this.initDone = true, 1000); + } + } + + @Component({ + template: 'child component', + standalone: true, + }) + class ChildCmp { + } + + TestBed.configureTestingModule({ + imports: [RouterTestingModule.withRoutes([ + {path: 'parent', component: ParentCmp, children: [{path: 'child', component: ChildCmp}]} + ])] + }); + const router = TestBed.inject(Router); + const fixture = createRoot(router, ParentCmp); + + advance(fixture, 250); + router.navigate(['parent/child']); + advance(fixture, 250); + // Not contain because initDone is still false + expect(fixture.nativeElement.innerHTML).not.toContain('child component'); + + advance(fixture, 1500); + router.navigate(['parent']); + advance(fixture, 1500); + // Not contain because route was changed back to parent + expect(fixture.nativeElement.innerHTML).not.toContain('child component'); + })); }); function advance(fixture: ComponentFixture, millis?: number): void {