From ea1968317e3f7072184b1e0703d9e8a501231755 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',