mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
fix(router): initial load waits until outlet attaches
This commit is contained in:
3
core/src/components.d.ts
vendored
3
core/src/components.d.ts
vendored
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -67,6 +67,9 @@ boolean
|
||||
#### ionNavWillChange
|
||||
|
||||
|
||||
#### ionNavWillLoad
|
||||
|
||||
|
||||
## Methods
|
||||
|
||||
#### canGoBack()
|
||||
|
||||
@@ -47,6 +47,9 @@ boolean
|
||||
#### ionNavWillChange
|
||||
|
||||
|
||||
#### ionNavWillLoad
|
||||
|
||||
|
||||
## Methods
|
||||
|
||||
#### commit()
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -233,6 +233,9 @@ Emitted when the tab changes.
|
||||
#### ionNavWillChange
|
||||
|
||||
|
||||
#### ionNavWillLoad
|
||||
|
||||
|
||||
## Methods
|
||||
|
||||
#### getRouteId()
|
||||
|
||||
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user