From a85915b28e59d420d20902c184bc859a8698026d Mon Sep 17 00:00:00 2001 From: markostanimirovic Date: Sat, 5 Nov 2022 01:59:24 +0100 Subject: [PATCH] feat(router-store): return resolved title via selectTitle --- .../spec/router_selectors.spec.ts | 62 +++++++++++++++++-- modules/router-store/src/router_selectors.ts | 12 ++-- .../src/serializers/minimal_serializer.ts | 2 + 3 files changed, 68 insertions(+), 8 deletions(-) diff --git a/modules/router-store/spec/router_selectors.spec.ts b/modules/router-store/spec/router_selectors.spec.ts index 48317c5c09..580e87d912 100644 --- a/modules/router-store/spec/router_selectors.spec.ts +++ b/modules/router-store/spec/router_selectors.spec.ts @@ -41,7 +41,6 @@ const mockData = { outlet: 'primary', routeConfig: { path: 'login', - title: 'Login', }, queryParams: { ref: 'ngrx.io', @@ -234,10 +233,65 @@ describe('Router State Selectors', () => { expect(result).toEqual(state.router.state.url); }); - it('should create a selector for getting the title', () => { - const result = selectors.selectTitle(state); + describe('selectTitle', () => { + it('should return undefined when route is not defined', () => { + const title = selectors.selectTitle({ + router: { state: { root: null }, navigationId: 1 }, + }); - expect(result).toEqual(state.router.state.routeConfig?.title); + expect(title).toBe(undefined); + }); + + it('should return undefined when route config is not defined', () => { + const title = selectors.selectTitle({ + router: { + state: { root: { routeConfig: null } }, + navigationId: 1, + }, + }); + + expect(title).toBe(undefined); + }); + + it('should return undefined when title is not defined', () => { + const title = selectors.selectTitle({ + router: { + state: { root: { routeConfig: {} } }, + navigationId: 1, + }, + }); + + expect(title).toBe(undefined); + }); + + it('should return static title', () => { + const staticTitle = 'Static Title'; + const title = selectors.selectTitle({ + router: { + state: { root: { routeConfig: { title: staticTitle } } }, + navigationId: 1, + }, + }); + + expect(title).toBe(staticTitle); + }); + + it('should return resolved title', () => { + const resolvedTitle = 'Resolved Title'; + const title = selectors.selectTitle({ + router: { + state: { + root: { + routeConfig: { title: class TitleResolver {} }, + title: resolvedTitle, + }, + }, + navigationId: 1, + }, + }); + + expect(title).toBe(resolvedTitle); + }); }); }); }); diff --git a/modules/router-store/src/router_selectors.ts b/modules/router-store/src/router_selectors.ts index 679d058b95..33d139e8c4 100644 --- a/modules/router-store/src/router_selectors.ts +++ b/modules/router-store/src/router_selectors.ts @@ -58,10 +58,14 @@ export function getSelectors>( selectRouterState, (routerState) => routerState && routerState.url ); - const selectTitle = createSelector( - selectCurrentRoute, - (route) => route && route.routeConfig?.title - ); + const selectTitle = createSelector(selectCurrentRoute, (route) => { + if (!route?.routeConfig) { + return undefined; + } + return typeof route.routeConfig.title === 'string' + ? route.routeConfig.title // static title + : route.title; // resolved title + }); return { selectCurrentRoute, diff --git a/modules/router-store/src/serializers/minimal_serializer.ts b/modules/router-store/src/serializers/minimal_serializer.ts index aaf8428904..f5cc8e530b 100644 --- a/modules/router-store/src/serializers/minimal_serializer.ts +++ b/modules/router-store/src/serializers/minimal_serializer.ts @@ -9,6 +9,7 @@ export interface MinimalActivatedRouteSnapshot { fragment: ActivatedRouteSnapshot['fragment']; data: ActivatedRouteSnapshot['data']; outlet: ActivatedRouteSnapshot['outlet']; + title: ActivatedRouteSnapshot['title']; firstChild?: MinimalActivatedRouteSnapshot; children: MinimalActivatedRouteSnapshot[]; } @@ -37,6 +38,7 @@ export class MinimalRouterStateSerializer data: route.data, url: route.url, outlet: route.outlet, + title: route.title, routeConfig: route.routeConfig ? { path: route.routeConfig.path,