fix(router): initial load waits until outlet attaches

This commit is contained in:
Manu Mtz.-Almeida
2018-04-30 14:18:06 +02:00
parent af4bcb8dcf
commit c905ba4611
9 changed files with 97 additions and 4 deletions

View File

@@ -3860,6 +3860,7 @@ declare global {
'delegate'?: FrameworkDelegate;
'onIonNavDidChange'?: (event: CustomEvent<void>) => void;
'onIonNavWillChange'?: (event: CustomEvent<void>) => void;
'onIonNavWillLoad'?: (event: CustomEvent<void>) => void;
'root'?: NavComponent;
'rootParams'?: ComponentProps;
'swipeBackEnabled'?: boolean;
@@ -5120,6 +5121,7 @@ declare global {
'delegate'?: FrameworkDelegate;
'onIonNavDidChange'?: (event: CustomEvent<void>) => void;
'onIonNavWillChange'?: (event: CustomEvent<void>) => void;
'onIonNavWillLoad'?: (event: CustomEvent<void>) => void;
}
}
}
@@ -6507,6 +6509,7 @@ declare global {
'onIonChange'?: (event: CustomEvent<{tab: HTMLIonTabElement}>) => void;
'onIonNavDidChange'?: (event: CustomEvent<void>) => void;
'onIonNavWillChange'?: (event: CustomEvent<void>) => void;
'onIonNavWillLoad'?: (event: CustomEvent<void>) => void;
'scrollable'?: boolean;
/**
* If true, the tabbar

View File

@@ -43,6 +43,7 @@ export class Nav implements NavOutlet {
}
}
@Event() ionNavWillLoad!: EventEmitter<void>;
@Event() ionNavWillChange!: EventEmitter<void>;
@Event() ionNavDidChange!: EventEmitter<void>;
@@ -54,6 +55,7 @@ export class Nav implements NavOutlet {
if (this.animated === undefined) {
this.animated = this.config.getBoolean('animate', true);
}
this.ionNavWillLoad.emit();
}
componentDidLoad() {

View File

@@ -67,6 +67,9 @@ boolean
#### ionNavWillChange
#### ionNavWillLoad
## Methods
#### canGoBack()

View File

@@ -47,6 +47,9 @@ boolean
#### ionNavWillChange
#### ionNavWillLoad
## Methods
#### commit()

View File

@@ -25,6 +25,7 @@ export class RouterOutlet implements NavOutlet {
@Prop() animationBuilder?: AnimationBuilder;
@Prop() delegate?: FrameworkDelegate;
@Event() ionNavWillLoad!: EventEmitter<void>;
@Event() ionNavWillChange!: EventEmitter<void>;
@Event() ionNavDidChange!: EventEmitter<void>;
@@ -32,6 +33,8 @@ export class RouterOutlet implements NavOutlet {
if (this.animated === undefined) {
this.animated = this.config.getBoolean('animate', true);
}
this.ionNavWillLoad.emit();
}
componentDidUnload() {

View File

@@ -1,6 +1,6 @@
import { Component, Element, Event, EventEmitter, Listen, Method, Prop } from '@stencil/core';
import { Config, QueueController } from '../../interface';
import { readNavState, writeNavState } from './utils/dom';
import { readNavState, waitUntilNavNode, writeNavState } from './utils/dom';
import { RouteChain, RouteRedirect, RouterDirection, RouterEventDetail } from './utils/interface';
import { routeRedirect, routerIDsToChain, routerPathToChain } from './utils/matching';
import { flattenRouterTree, readRedirects, readRoutes } from './utils/parser';
@@ -55,6 +55,8 @@ export class Router {
async componentWillLoad() {
console.debug('[ion-router] router will load');
await waitUntilNavNode(this.win);
console.debug('[ion-router] found nav');
const tree = readRoutes(this.el);
this.routes = flattenRouterTree(tree);
@@ -68,7 +70,6 @@ export class Router {
componentDidLoad() {
this.init = true;
console.debug('[ion-router] router did load');
}

View File

@@ -1,5 +1,5 @@
import { RouteChain } from '../utils/interface';
import { chainToPath, generatePath, parsePath, readPath } from '../utils/path';
import { RouteChain, RouterDirection } from '../utils/interface';
import { chainToPath, generatePath, parsePath, readPath, writePath } from '../utils/path';
describe('parseURL', () => {
it('should parse empty path', () => {
@@ -176,6 +176,78 @@ describe('readPath', () => {
});
});
describe('writePath', () => {
it('should write root path (no hash)', () => {
const history = mockHistory();
writePath(history, '', false, [''], RouterDirection.Forward, 123);
expect(history.pushState).toHaveBeenCalledWith(123, '', '/');
writePath(history, '', false, ['schedule'], RouterDirection.Forward, 123);
expect(history.pushState).toHaveBeenCalledWith(123, '', '/schedule');
writePath(history, '/', false, [''], RouterDirection.Forward, 123);
expect(history.pushState).toHaveBeenCalledWith(123, '', '/');
writePath(history, '/', false, ['to', 'schedule'], RouterDirection.Forward, 123);
expect(history.pushState).toHaveBeenCalledWith(123, '', '/to/schedule');
});
it('should write non root path (no hash)', () => {
const history = mockHistory();
writePath(history, '/path', false, [''], RouterDirection.Forward, 2);
expect(history.pushState).toHaveBeenCalledWith(2, '', '/path');
writePath(history, '/path', false, ['to', 'page'], RouterDirection.Forward, 2);
expect(history.pushState).toHaveBeenCalledWith(2, '', '/path/to/page');
writePath(history, 'path/to', false, ['second', 'page'], RouterDirection.Forward, 2);
expect(history.pushState).toHaveBeenCalledWith(2, '', '/path/to/second/page');
writePath(history, '/path/to/', false, ['second', 'page'], RouterDirection.Forward, 2);
expect(history.pushState).toHaveBeenCalledWith(2, '', '/path/to/second/page');
});
it('should write root path (no hash)', () => {
const history = mockHistory();
writePath(history, '', true, [''], RouterDirection.Forward, 123);
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/');
writePath(history, '', true, ['schedule'], RouterDirection.Forward, 123);
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/schedule');
writePath(history, '/', true, [''], RouterDirection.Forward, 123);
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/');
writePath(history, '/', true, ['to', 'schedule'], RouterDirection.Forward, 123);
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/to/schedule');
});
it('should write non root path (no hash)', () => {
const history = mockHistory();
writePath(history, '/path', true, [''], RouterDirection.Forward, 123);
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/path');
writePath(history, '/path', true, ['to', 'page'], RouterDirection.Forward, 123);
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/path/to/page');
writePath(history, 'path/to', true, ['second', 'page'], RouterDirection.Forward, 123);
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/path/to/second/page');
writePath(history, '/path/to/', true, ['second', 'page'], RouterDirection.Forward, 123);
expect(history.pushState).toHaveBeenCalledWith(123, '', '#/path/to/second/page');
});
});
function mockHistory(): History {
return {
replaceState: jest.fn(),
pushState: jest.fn(),
length: 0,
} as any;
}
function mockLocation(pathname: string, hash: string): Location {
return {
pathname,

View File

@@ -233,6 +233,9 @@ Emitted when the tab changes.
#### ionNavWillChange
#### ionNavWillLoad
## Methods
#### getRouteId()

View File

@@ -70,6 +70,7 @@ export class Tabs implements NavOutlet {
* Emitted when the tab changes.
*/
@Event() ionChange!: EventEmitter<{tab: HTMLIonTabElement}>;
@Event() ionNavWillLoad!: EventEmitter<void>;
@Event() ionNavWillChange!: EventEmitter<void>;
@Event() ionNavDidChange!: EventEmitter<void>;
@@ -81,6 +82,8 @@ export class Tabs implements NavOutlet {
this.loadConfig('tabbarLayout', 'bottom');
this.loadConfig('tabbarLayout', 'icon-top');
this.loadConfig('tabbarHighlight', false);
this.ionNavWillLoad.emit();
}
async componentDidLoad() {