From 771f7318f025452e6c1707a94f8d80e001ae17dc Mon Sep 17 00:00:00 2001 From: Zack Birkenbuel Date: Tue, 29 Sep 2020 09:10:11 -0700 Subject: [PATCH] fix(router): update getRouteGuards to check if the context outlet is activated (#39049) In certain circumstances (errors during component constructor) the router outlet may not be activated before redirecting to a new route. If the new route requires running guards and resolvers the current logic will throw when accessing outlet.component due to an isActivated check within the property getter. This update brings the logic inline with deactivateRouterAndItsChildren, namely checking outlet.isActivated before trying to access outlet.component. Fixes #39030 PR Close #39049 --- packages/router/src/utils/preactivation.ts | 5 ++--- packages/router/test/integration.spec.ts | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/router/src/utils/preactivation.ts b/packages/router/src/utils/preactivation.ts index 0334810748..09e87c8ef5 100644 --- a/packages/router/src/utils/preactivation.ts +++ b/packages/router/src/utils/preactivation.ts @@ -121,9 +121,8 @@ function getRouteGuards( getChildRouteGuards(futureNode, currNode, parentContexts, futurePath, checks); } - if (shouldRun) { - const component = context && context.outlet && context.outlet.component || null; - checks.canDeactivateChecks.push(new CanDeactivate(component, curr)); + if (shouldRun && context && context.outlet && context.outlet.isActivated) { + checks.canDeactivateChecks.push(new CanDeactivate(context.outlet.component, curr)); } } else { if (curr) { diff --git a/packages/router/test/integration.spec.ts b/packages/router/test/integration.spec.ts index 580360f333..6c5e5e5d89 100644 --- a/packages/router/test/integration.spec.ts +++ b/packages/router/test/integration.spec.ts @@ -3027,6 +3027,13 @@ describe('Integration', () => { resolve: {data: 'resolver'}, }, ] + }, + { + path: 'throwing', + runGuardsAndResolvers, + component: ThrowingCmp, + canActivate: ['guard'], + resolve: {data: 'resolver'} } ]); @@ -3125,6 +3132,15 @@ describe('Integration', () => { advance(fixture); expect(guardRunCount).toEqual(5); expect(recordedData).toEqual([{data: 0}, {data: 1}, {data: 2}, {data: 3}, {data: 4}]); + + // Issue #39030, always running guards and resolvers should not throw + // when navigating away from a component with a throwing constructor. + expect(() => { + router.navigateByUrl('/throwing').catch(() => {}); + advance(fixture); + router.navigateByUrl('/a;p=1'); + advance(fixture); + }).not.toThrow(); }))); it('should rerun rerun guards and resolvers when path params change',