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
This commit is contained in:
Jan Cabadaj
2023-03-17 10:43:12 +01:00
committed by Andrew Scott
parent 4d455e06c7
commit d3018c0ee7
2 changed files with 50 additions and 6 deletions
@@ -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;
}
@@ -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: '<div *ngIf="initDone"><router-outlet></router-outlet></div>',
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<unknown>, millis?: number): void {