Skip to content

Commit d3018c0

Browse files
jancabadajatscott
authored andcommitted
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
1 parent 4d455e0 commit d3018c0

File tree

2 files changed

+50
-6
lines changed

2 files changed

+50
-6
lines changed

packages/router/src/operators/activate_routes.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,16 @@ export class ActivateRoutes {
126126
this.deactivateRouteAndItsChildren(children[childOutlet], contexts);
127127
}
128128

129-
if (context && context.outlet) {
130-
// Destroy the component
131-
context.outlet.deactivate();
132-
// Destroy the contexts for all the outlets that were in the component
133-
context.children.onOutletDeactivated();
129+
if (context) {
130+
if (context.outlet) {
131+
// Destroy the component
132+
context.outlet.deactivate();
133+
// Destroy the contexts for all the outlets that were in the component
134+
context.children.onOutletDeactivated();
135+
}
134136
// Clear the information about the attached component on the context but keep the reference to
135-
// the outlet.
137+
// the outlet. Clear even if outlet was not yet activated to avoid activating later with old
138+
// info
136139
context.attachRef = null;
137140
context.route = null;
138141
}

packages/router/test/directives/router_outlet.spec.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,47 @@ describe('router outlet name', () => {
149149
advance(fixture);
150150
expect(fixture.nativeElement.innerHTML).toMatch('.*component 3.*component 2.*component 1');
151151
}));
152+
153+
it('should not activate if route is changed', fakeAsync(() => {
154+
@Component({
155+
standalone: true,
156+
template: '<div *ngIf="initDone"><router-outlet></router-outlet></div>',
157+
imports: [RouterOutlet, CommonModule],
158+
})
159+
class ParentCmp {
160+
initDone = false;
161+
constructor() {
162+
setTimeout(() => this.initDone = true, 1000);
163+
}
164+
}
165+
166+
@Component({
167+
template: 'child component',
168+
standalone: true,
169+
})
170+
class ChildCmp {
171+
}
172+
173+
TestBed.configureTestingModule({
174+
imports: [RouterTestingModule.withRoutes([
175+
{path: 'parent', component: ParentCmp, children: [{path: 'child', component: ChildCmp}]}
176+
])]
177+
});
178+
const router = TestBed.inject(Router);
179+
const fixture = createRoot(router, ParentCmp);
180+
181+
advance(fixture, 250);
182+
router.navigate(['parent/child']);
183+
advance(fixture, 250);
184+
// Not contain because initDone is still false
185+
expect(fixture.nativeElement.innerHTML).not.toContain('child component');
186+
187+
advance(fixture, 1500);
188+
router.navigate(['parent']);
189+
advance(fixture, 1500);
190+
// Not contain because route was changed back to parent
191+
expect(fixture.nativeElement.innerHTML).not.toContain('child component');
192+
}));
152193
});
153194

154195
function advance(fixture: ComponentFixture<unknown>, millis?: number): void {

0 commit comments

Comments
 (0)