From 3ce8a674097516630a36a2e13f6d30aac621725b Mon Sep 17 00:00:00 2001 From: "Manu Mtz.-Almeida" Date: Thu, 8 Mar 2018 13:12:50 +0100 Subject: [PATCH] feat(router): reverse lookup with params --- packages/core/src/components/nav/nav.tsx | 14 ++++--- packages/core/src/components/nav/readme.md | 2 +- .../core/src/components/router/router.tsx | 32 +++++++------- .../src/components/router/test/e2e.spec.tsx | 38 ++++++++++++----- .../components/router/test/matching.spec.tsx | 42 +++++-------------- .../components/router/test/parser.spec.tsx | 26 ++++++------ .../src/components/router/test/path.spec.tsx | 39 ++++++++++++++++- .../src/components/router/utils/common.ts | 7 ---- .../core/src/components/router/utils/dom.ts | 19 ++++----- .../src/components/router/utils/interfaces.ts | 10 ++--- .../src/components/router/utils/matching.ts | 30 ++++++------- .../src/components/router/utils/parser.ts | 2 +- .../core/src/components/router/utils/path.ts | 16 ++++--- packages/core/src/components/tab/readme.md | 2 +- packages/core/src/components/tab/tab.tsx | 6 +-- packages/core/src/components/tabs/readme.md | 2 +- packages/core/src/components/tabs/tabs.tsx | 13 +++--- 17 files changed, 167 insertions(+), 133 deletions(-) diff --git a/packages/core/src/components/nav/nav.tsx b/packages/core/src/components/nav/nav.tsx index 6da72244ba..711cf4545b 100644 --- a/packages/core/src/components/nav/nav.tsx +++ b/packages/core/src/components/nav/nav.tsx @@ -25,6 +25,7 @@ import { Transition } from './transition'; import iosTransitionAnimation from './animations/ios.transition'; import mdTransitionAnimation from './animations/md.transition'; +import { RouteID } from '../router/utils/interfaces'; const TrnsCtrl = new TransitionController(); @@ -215,16 +216,19 @@ export class NavControllerBase implements NavOutlet { } @Method() - getRouteId(): string | null { - const element = this.getContentElement(); - if (element) { - return element.tagName; + getRouteId(): RouteID|null { + const active = this.getActive(); + if (active) { + return { + id: active.element.tagName, + params: active.data + }; } return null; } @Method() - getContentElement(): HTMLElement { + getContainerEl(): HTMLElement { const active = this.getActive(); if (active) { return active.element; diff --git a/packages/core/src/components/nav/readme.md b/packages/core/src/components/nav/readme.md index e93d32fb64..86900d85bb 100644 --- a/packages/core/src/components/nav/readme.md +++ b/packages/core/src/components/nav/readme.md @@ -48,7 +48,7 @@ boolean #### getByIndex() -#### getContentElement() +#### getContainerEl() #### getPrevious() diff --git a/packages/core/src/components/router/router.tsx b/packages/core/src/components/router/router.tsx index 37e85e931a..44883b4648 100644 --- a/packages/core/src/components/router/router.tsx +++ b/packages/core/src/components/router/router.tsx @@ -52,16 +52,20 @@ export class Router { } console.debug('[IN] nav changed -> update URL'); const { ids, pivot } = this.readNavState(); - const { chain, matches } = routerIDsToChain(ids, this.routes); - if (chain.length > matches) { - // readNavState() found a pivot that is not initialized - console.debug('[IN] pivot uninitialized -> write partial nav state'); - this.writeNavState(pivot, chain.slice(matches), 0); - } + const chain = routerIDsToChain(ids, this.routes); + if (chain) { + if (chain.length > ids.length) { + // readNavState() found a pivot that is not initialized + console.debug('[IN] pivot uninitialized -> write partial nav state'); + this.writeNavState(pivot, chain.slice(ids.length), 0); + } - const isPop = ev.detail.isPop === true; - const path = chainToPath(chain); - this.writePath(path, isPop); + const isPop = ev.detail.isPop === true; + const path = chainToPath(chain); + this.writePath(path, isPop); + } else { + console.warn('no matching URL for ', ids.map(i => i.id)); + } } @Method() @@ -80,7 +84,7 @@ export class Router { } const direction = window.history.state >= this.state ? 1 : -1; const node = document.querySelector('ion-app'); - const {chain} = routerPathToChain(currentPath, this.routes); + const chain = routerPathToChain(currentPath, this.routes); return this.writeNavState(node, chain, direction); } @@ -100,14 +104,12 @@ export class Router { } private writePath(path: string[], isPop: boolean) { - this.state = writePath(window.history, this.base, this.useHash, path, isPop, this.state); + // busyURL is used to prevent reentering in the popstate event + this.state++; + writePath(window.history, this.base, this.useHash, path, isPop, this.state); } private readPath(): string[] | null { return readPath(window.location, this.base, this.useHash); } - - render() { - return ; - } } diff --git a/packages/core/src/components/router/test/e2e.spec.tsx b/packages/core/src/components/router/test/e2e.spec.tsx index 81ef9d790a..87004e97fe 100644 --- a/packages/core/src/components/router/test/e2e.spec.tsx +++ b/packages/core/src/components/router/test/e2e.spec.tsx @@ -1,4 +1,4 @@ -import { RouteChain } from '../utils/interfaces'; +import { RouteChain, RouteID } from '../utils/interfaces'; import { routerIDsToChain, routerPathToChain } from '../utils/matching'; import { mockRouteElement } from './parser.spec'; import { chainToPath, generatePath, parsePath } from '../utils/path'; @@ -18,19 +18,37 @@ describe('ionic-conference-app', () => { expect(getRouteIDs('/about', routes)).toEqual(['page-tabs', 'page-about']); expect(getRouteIDs('/tutorial', routes)).toEqual(['page-tutorial']); - expect(getRoutePaths(['page-tabs', 'tab-schedule', 'page-schedule'], routes)).toEqual('/'); - expect(getRoutePaths(['page-tabs', 'tab-speaker', 'page-speaker-list'], routes)).toEqual('/speaker'); - expect(getRoutePaths(['page-tabs', 'page-map'], routes)).toEqual('/map'); - expect(getRoutePaths(['page-tabs', 'page-about'], routes)).toEqual('/about'); - expect(getRoutePaths(['page-tutorial'], routes)).toEqual('/tutorial'); + expect(getRoutePath([ + {id: 'PAGE-TABS'}, + {id: 'tab-schedule'}, + {id: 'page-schedule'}], routes)).toEqual('/'); + expect(getRoutePath([ + {id: 'page-tabs'}, + {id: 'TAB-SPEAKER'}], routes)).toEqual('/speaker'); + + expect(getRoutePath([ + {id: 'page-tabs'}, + {id: 'TAB-SPEAKER'}, + {id: 'page-speaker-list'}], routes)).toEqual('/speaker'); + + expect(getRoutePath([ + {id: 'page-tabs'}, + {id: 'PAGE-MAP'}], routes)).toEqual('/map'); + + expect(getRoutePath([ + {id: 'page-tabs'}, + {id: 'page-about'}], routes)).toEqual('/about'); + + expect(getRoutePath([ + {id: 'page-tutorial'}], routes)).toEqual('/tutorial'); }); }); function conferenceAppRouting() { const p2 = mockRouteElement('/', 'tab-schedule'); - const p3 = mockRouteElement('/', 'page-schedule'); + const p3 = mockRouteElement('/', 'PAGE-SCHEDULE'); p2.appendChild(p3); const p4 = mockRouteElement('/speaker', 'tab-speaker'); @@ -56,10 +74,10 @@ function conferenceAppRouting() { function getRouteIDs(path: string, routes: RouteChain[]): string[] { - return routerPathToChain(parsePath(path), routes).chain.map(r => r.id); + return routerPathToChain(parsePath(path), routes).map(r => r.id); } -function getRoutePaths(ids: string[], routes: RouteChain[]): string { - return generatePath(chainToPath(routerIDsToChain(ids, routes).chain)); +function getRoutePath(ids: RouteID[], routes: RouteChain[]): string { + return generatePath(chainToPath(routerIDsToChain(ids, routes))); } diff --git a/packages/core/src/components/router/test/matching.spec.tsx b/packages/core/src/components/router/test/matching.spec.tsx index 535a856b3d..0370bcb508 100644 --- a/packages/core/src/components/router/test/matching.spec.tsx +++ b/packages/core/src/components/router/test/matching.spec.tsx @@ -132,34 +132,12 @@ describe('routerPathToChain', () => { chain3, chain4 ]; - expect(routerPathToChain(['to'], routes)).toEqual({ - chain: null, - matches: 0, - }); - - expect(routerPathToChain([''], routes)).toEqual({ - chain: null, - matches: 0, - }); - expect(routerPathToChain(['segment', 'to'], routes)).toEqual({ - chain: null, - matches: 0, - }); - - expect(routerPathToChain(['hola'], routes)).toEqual({ - chain: chain3, - matches: 1, - }); - expect(routerPathToChain(['hola', 'hola'], routes)).toEqual({ - chain: chain3, - matches: 1, - }); - - expect(routerPathToChain(['hola', 'adios'], routes)).toEqual({ - chain: chain4, - matches: 2, - }); - + expect(routerPathToChain(['to'], routes)).toEqual(null); + expect(routerPathToChain([''], routes)).toEqual(null); + expect(routerPathToChain(['segment', 'to'], routes)).toEqual(null); + expect(routerPathToChain(['hola'], routes)).toEqual(chain3); + expect(routerPathToChain(['hola', 'hola'], routes)).toEqual(chain3); + expect(routerPathToChain(['hola', 'adios'], routes)).toEqual(chain4); }); it('should match the default route', () => { @@ -174,11 +152,11 @@ describe('routerPathToChain', () => { { id: 'page2', path: [''], params: undefined } ]; - expect(routerPathToChain([''], [chain1])).toEqual({chain: chain1, matches: 3}); - expect(routerPathToChain(['tab2'], [chain1])).toEqual({chain: null, matches: 0}); + expect(routerPathToChain([''], [chain1])).toEqual(chain1); + expect(routerPathToChain(['tab2'], [chain1])).toEqual(null); - expect(routerPathToChain([''], [chain2])).toEqual({chain: null, matches: 0}); - expect(routerPathToChain(['tab2'], [chain2])).toEqual({chain: chain2, matches: 3}); + expect(routerPathToChain([''], [chain2])).toEqual(null); + expect(routerPathToChain(['tab2'], [chain2])).toEqual(chain2); }); }); diff --git a/packages/core/src/components/router/test/parser.spec.tsx b/packages/core/src/components/router/test/parser.spec.tsx index be163f33f0..c8ab9938dc 100644 --- a/packages/core/src/components/router/test/parser.spec.tsx +++ b/packages/core/src/components/router/test/parser.spec.tsx @@ -5,7 +5,7 @@ import { RouteTree } from '../utils/interfaces'; describe('readRoutes', () => { it('should read URL', () => { const root = mockElement('div'); - const r1 = mockRouteElement('/', 'main-page'); + const r1 = mockRouteElement('/', 'MAIN-PAGE'); const r2 = mockRouteElement('/one-page', 'one-page'); const r3 = mockRouteElement('secondpage', 'second-page'); const r4 = mockRouteElement('/5/hola', '4'); @@ -20,12 +20,12 @@ describe('readRoutes', () => { r4.appendChild(r6); const expected: RouteTree = [ - { path: [''], id: 'main-page', children: [], props: undefined }, - { path: ['one-page'], id: 'one-page', children: [], props: undefined }, - { path: ['secondpage'], id: 'second-page', props: undefined, children: [ - { path: ['5', 'hola'], id: '4', props: undefined, children: [ - { path: ['path', 'to', 'five'], id: '5', children: [], props: undefined }, - { path: ['path', 'to', 'five2'], id: '6', children: [], props: undefined } + { path: [''], id: 'main-page', children: [], params: undefined }, + { path: ['one-page'], id: 'one-page', children: [], params: undefined }, + { path: ['secondpage'], id: 'second-page', params: undefined, children: [ + { path: ['5', 'hola'], id: '4', params: undefined, children: [ + { path: ['path', 'to', 'five'], id: '5', children: [], params: undefined }, + { path: ['path', 'to', 'five2'], id: '6', children: [], params: undefined } ] } ] } ]; @@ -36,12 +36,12 @@ describe('readRoutes', () => { describe('flattenRouterTree', () => { it('should process routes', () => { const entries: RouteTree = [ - { path: [''], id: 'hola', children: [], props: undefined }, - { path: ['one-page'], id: 'one-page', children: [], props: undefined }, - { path: ['secondpage'], id: 'second-page', props: undefined, children: [ - { path: ['5', 'hola'], id: '4', props: undefined, children: [ - { path: ['path', 'to', 'five'], id: '5', children: [], props: undefined }, - { path: ['path', 'to', 'five2'], id: '6', children: [], props: undefined } + { path: [''], id: 'hola', children: [], params: undefined }, + { path: ['one-page'], id: 'one-page', children: [], params: undefined }, + { path: ['secondpage'], id: 'second-page', params: undefined, children: [ + { path: ['5', 'hola'], id: '4', params: undefined, children: [ + { path: ['path', 'to', 'five'], id: '5', children: [], params: undefined }, + { path: ['path', 'to', 'five2'], id: '6', children: [], params: undefined } ] } ] } ]; diff --git a/packages/core/src/components/router/test/path.spec.tsx b/packages/core/src/components/router/test/path.spec.tsx index 4fe3ff7ee4..dd4f9e2fa4 100644 --- a/packages/core/src/components/router/test/path.spec.tsx +++ b/packages/core/src/components/router/test/path.spec.tsx @@ -1,4 +1,5 @@ -import { generatePath, parsePath } from '../utils/path'; +import { chainToPath, generatePath, parsePath } from '../utils/path'; +import { RouteChain } from '../utils/interfaces'; describe('parseURL', () => { it('should parse empty path', () => { @@ -53,3 +54,39 @@ describe('generatePath', () => { }); }); + + +describe('chainToPath', () => { + it('should generate a simple URL', () => { + const chain: RouteChain = [ + { id: '2', path: [''], params: undefined }, + { id: '1', path: [''], params: undefined }, + { id: '3', path: ['segment', 'to'], params: undefined }, + { id: '4', path: [''], params: undefined }, + { id: '5', path: ['hola', '', 'hey'], params: undefined }, + { id: '6', path: [''], params: undefined }, + { id: '7', path: [':param'], params: {param: 'name'} }, + { id: '8', path: ['adios', ':name', ':id'], params: {name: 'manu', id: '123'} }, + ]; + expect(chainToPath(chain)).toEqual( + ['segment', 'to', 'hola', 'hey', 'name', 'adios', 'manu', '123'] + ); + }); + + it('should raise an exception', () => { + const chain: RouteChain = [ + { id: '3', path: ['segment'], params: undefined }, + { id: '8', path: [':name'], params: undefined }, + ]; + expect(() => chainToPath(chain)).toThrowError('missing param name'); + }); + + it('should raise an exception 2', () => { + const chain: RouteChain = [ + { id: '3', path: ['segment'], params: undefined }, + { id: '8', path: [':name', ':id'], params: {name: 'hey'} }, + ]; + expect(() => chainToPath(chain)).toThrowError('missing param id'); + }); +}); + diff --git a/packages/core/src/components/router/utils/common.ts b/packages/core/src/components/router/utils/common.ts index d8631c32b4..a766a3fd51 100644 --- a/packages/core/src/components/router/utils/common.ts +++ b/packages/core/src/components/router/utils/common.ts @@ -6,13 +6,6 @@ export class RouterSegments { this.path = path.slice(); } - isDefault(): boolean { - if (this.path.length > 0) { - return this.path[0] === ''; - } - return true; - } - next(): string { if (this.path.length > 0) { return this.path.shift() as string; diff --git a/packages/core/src/components/router/utils/dom.ts b/packages/core/src/components/router/utils/dom.ts index d124bce3c3..76f998bcc5 100644 --- a/packages/core/src/components/router/utils/dom.ts +++ b/packages/core/src/components/router/utils/dom.ts @@ -1,5 +1,5 @@ import { breadthFirstSearch } from './common'; -import { NavOutlet, RouteChain } from './interfaces'; +import { NavOutlet, RouteChain, RouteID } from './interfaces'; export function writeNavState(root: HTMLElement, chain: RouteChain|null, index: number, direction: number): Promise { if (!chain || index >= chain.length) { @@ -16,7 +16,7 @@ export function writeNavState(root: HTMLElement, chain: RouteChain|null, index: if (changed) { direction = 0; } - const nextEl = node.getContentElement(); + const nextEl = node.getContainerEl(); const promise = (nextEl) ? writeNavState(nextEl, chain, index + 1, direction) : Promise.resolve(); @@ -29,15 +29,15 @@ export function writeNavState(root: HTMLElement, chain: RouteChain|null, index: } export function readNavState(node: HTMLElement) { - const stack: string[] = []; + const ids: RouteID[] = []; let pivot: NavOutlet|null; while (true) { pivot = breadthFirstSearch(node); if (pivot) { - const cmp = pivot.getRouteId(); - if (cmp) { - node = pivot.getContentElement(); - stack.push(cmp.toLowerCase()); + const id = pivot.getRouteId(); + if (id) { + node = pivot.getContainerEl(); + ids.push(id); } else { break; } @@ -45,8 +45,5 @@ export function readNavState(node: HTMLElement) { break; } } - return { - ids: stack, - pivot: pivot, - }; + return {ids, pivot}; } diff --git a/packages/core/src/components/router/utils/interfaces.ts b/packages/core/src/components/router/utils/interfaces.ts index c25b37d093..c7680e0aa9 100644 --- a/packages/core/src/components/router/utils/interfaces.ts +++ b/packages/core/src/components/router/utils/interfaces.ts @@ -2,14 +2,14 @@ export interface NavOutlet { setRouteId(id: string, data: any, direction: number): Promise; markVisible?(): Promise; - getRouteId(): string; + getRouteId(): RouteID|null; - getContentElement(): HTMLElement | null; + getContainerEl(): HTMLElement | null; } -export interface RouteMatch { - chain: RouteChain; - matches: number; +export interface RouteID { + id: string; + params?: any; } export type NavOutletElement = NavOutlet & HTMLStencilElement; diff --git a/packages/core/src/components/router/utils/matching.ts b/packages/core/src/components/router/utils/matching.ts index da028b288e..12a5dea8b5 100644 --- a/packages/core/src/components/router/utils/matching.ts +++ b/packages/core/src/components/router/utils/matching.ts @@ -1,11 +1,11 @@ import { RouterSegments } from './common'; -import { RouteChain, RouteMatch } from './interfaces'; +import { RouteChain, RouteID } from './interfaces'; export function matchesIDs(ids: string[], chain: RouteChain): number { const len = Math.min(ids.length, chain.length); let i = 0; for (; i < len; i++) { - if (ids[i] !== chain[i].id) { + if (ids[i].toLowerCase() !== chain[i].id) { break; } } @@ -40,7 +40,7 @@ export function matchesPath(path: string[], chain: RouteChain): RouteChain | nul } } const matches = (matchesDefault) - ? matchesDefault === segments.isDefault() + ? matchesDefault === (segments.next() === '') : true; if (!matches) { @@ -71,24 +71,29 @@ export function mergeParams(a: any, b: any): any { } -export function routerIDsToChain(ids: string[], chains: RouteChain[]): RouteMatch { +export function routerIDsToChain(ids: RouteID[], chains: RouteChain[]): RouteChain|null { let match: RouteChain|null = null; let maxMatches = 0; + const plainIDs = ids.map(i => i.id); for (const chain of chains) { - const score = matchesIDs(ids, chain); + const score = matchesIDs(plainIDs, chain); if (score > maxMatches) { match = chain; maxMatches = score; } } - return { - chain: match, - matches: maxMatches - }; + if (match) { + return match.map((route, i) => ({ + id: route.id, + path: route.path, + params: mergeParams(route.params, ids[i] && ids[i].params) + })); + } + return null; } -export function routerPathToChain(path: string[], chains: RouteChain[]): RouteMatch|null { +export function routerPathToChain(path: string[], chains: RouteChain[]): RouteChain|null { let match: RouteChain = null; let matches = 0; for (const chain of chains) { @@ -100,8 +105,5 @@ export function routerPathToChain(path: string[], chains: RouteChain[]): RouteMa } } } - return { - chain: match, - matches, - }; + return match; } diff --git a/packages/core/src/components/router/utils/parser.ts b/packages/core/src/components/router/utils/parser.ts index 33b31e3a4b..19e39a393d 100644 --- a/packages/core/src/components/router/utils/parser.ts +++ b/packages/core/src/components/router/utils/parser.ts @@ -7,7 +7,7 @@ export function readRoutes(root: Element): RouteTree { .filter(el => el.tagName === 'ION-ROUTE') .map(el => ({ path: parsePath(readProp(el, 'path')), - id: readProp(el, 'component'), + id: readProp(el, 'component').toLowerCase(), params: el.params, children: readRoutes(el) })); diff --git a/packages/core/src/components/router/utils/path.ts b/packages/core/src/components/router/utils/path.ts index 9c5d436bf2..e5b02652c4 100644 --- a/packages/core/src/components/router/utils/path.ts +++ b/packages/core/src/components/router/utils/path.ts @@ -11,8 +11,16 @@ export function generatePath(segments: string[]): string { export function chainToPath(chain: RouteChain): string[] { const path = []; for (const route of chain) { - if (route.path[0] !== '') { - path.push(...route.path); + for (const segment of route.path) { + if (segment[0] === ':') { + const param = route.params && route.params[segment.slice(1)]; + if (!param) { + throw new Error(`missing param ${segment.slice(1)}`); + } + path.push(param); + } else if (segment !== '') { + path.push(segment); + } } } return path; @@ -24,14 +32,12 @@ export function writePath(history: History, base: string, usePath: boolean, path if (usePath) { url = '#' + url; } - state++; if (isPop) { - history.back(); + // history.back(); history.replaceState(state, null, url); } else { history.pushState(state, null, url); } - return state; } export function readPath(loc: Location, base: string, useHash: boolean): string[] | null { diff --git a/packages/core/src/components/tab/readme.md b/packages/core/src/components/tab/readme.md index b504b44113..738b2851b0 100644 --- a/packages/core/src/components/tab/readme.md +++ b/packages/core/src/components/tab/readme.md @@ -235,7 +235,7 @@ Emitted when the current tab is selected. ## Methods -#### getRouteId() +#### getTabId() #### setActive() diff --git a/packages/core/src/components/tab/tab.tsx b/packages/core/src/components/tab/tab.tsx index e9b5df7a2c..2836d5d39a 100644 --- a/packages/core/src/components/tab/tab.tsx +++ b/packages/core/src/components/tab/tab.tsx @@ -1,6 +1,4 @@ import { Component, Element, Event, EventEmitter, Method, Prop, State, Watch } from '@stencil/core'; -import { asyncRaf } from '../../utils/helpers'; - @Component({ tag: 'ion-tab', @@ -86,7 +84,7 @@ export class Tab { @Event() ionSelect: EventEmitter; @Method() - getRouteId(): string|null { + getTabId(): string|null { if (this.name) { return this.name; } @@ -104,7 +102,7 @@ export class Tab { private prepareLazyLoaded(): Promise { if (!this.loaded && this.component) { this.loaded = true; - return attachViewToDom(this.el, this.component).then(() => asyncRaf()); + return attachViewToDom(this.el, this.component); } return Promise.resolve(); } diff --git a/packages/core/src/components/tabs/readme.md b/packages/core/src/components/tabs/readme.md index 5e099a2b7b..83a76498e6 100644 --- a/packages/core/src/components/tabs/readme.md +++ b/packages/core/src/components/tabs/readme.md @@ -222,7 +222,7 @@ Emitted when the tab changes. ## Methods -#### getContentElement() +#### getContainerEl() #### getRouteId() diff --git a/packages/core/src/components/tabs/tabs.tsx b/packages/core/src/components/tabs/tabs.tsx index a6a9ebee7b..96e8dc6642 100644 --- a/packages/core/src/components/tabs/tabs.tsx +++ b/packages/core/src/components/tabs/tabs.tsx @@ -1,5 +1,6 @@ import { Component, Element, Event, EventEmitter, Listen, Method, Prop, State } from '@stencil/core'; import { Config, NavOutlet } from '../../index'; +import { RouteID } from '../router/utils/interfaces'; @Component({ @@ -101,7 +102,7 @@ export class Tabs implements NavOutlet { @Method() getTab(tabOrIndex: string | number | HTMLIonTabElement): HTMLIonTabElement { if (typeof tabOrIndex === 'string') { - return this.tabs.find(tab => tab.getRouteId() === tabOrIndex); + return this.tabs.find(tab => tab.getTabId() === tabOrIndex); } if (typeof tabOrIndex === 'number') { return this.tabs[tabOrIndex]; @@ -136,16 +137,14 @@ export class Tabs implements NavOutlet { } @Method() - getRouteId(): string|null { - if (this.selectedTab) { - return this.selectedTab.getRouteId(); - } - return null; + getRouteId(): RouteID|null { + const id = this.selectedTab && this.selectedTab.getTabId(); + return id ? {id} : null; } @Method() - getContentElement(): HTMLElement { + getContainerEl(): HTMLElement { return this.routingView || this.selectedTab; }