diff --git a/packages/core/scripts/test-components/src/components/page-one/page-one.tsx b/packages/core/scripts/test-components/src/components/page-one/page-one.tsx
index fa460b3f67..dc7d31b48c 100644
--- a/packages/core/scripts/test-components/src/components/page-one/page-one.tsx
+++ b/packages/core/scripts/test-components/src/components/page-one/page-one.tsx
@@ -15,6 +15,7 @@ export class PageOne {
page one
+ Ir a la page 2
];
diff --git a/packages/core/src/components/nav/nav.tsx b/packages/core/src/components/nav/nav.tsx
index 31156be6cf..f4fe878fc0 100644
--- a/packages/core/src/components/nav/nav.tsx
+++ b/packages/core/src/components/nav/nav.tsx
@@ -193,13 +193,25 @@ export class Nav implements PublicNav, NavOutlet {
}
@Method()
- setRouteId(id: string, _: any = {}): Promise {
- assert(this.useRouter, 'routing is disabled');
+ setRouteId(id: string, _: any = {}, direction: number): Promise {
const active = this.getActive();
if (active && active.component === id) {
- return Promise.resolve(null);
+ return Promise.resolve(false);
}
- return this.setRoot(id);
+ if (direction === 1) {
+ return this.push(id).then(() => true);
+ } else if (direction === -1 && this._canGoBack(id)) {
+ return this.pop().then(() => true);
+ }
+ return this.setRoot(id).then(() => true);
+ }
+
+ private _canGoBack(id: any) {
+ if (!this.canGoBack()) {
+ return false;
+ }
+ const view = this.views[this.views.length - 1];
+ return view.component === id;
}
@Method()
@@ -215,7 +227,7 @@ export class Nav implements PublicNav, NavOutlet {
getContentElement(): HTMLElement {
const active = getActiveImpl(this);
if (active) {
- active.element;
+ return active.element;
}
return null;
}
diff --git a/packages/core/src/components/router/router-utils.ts b/packages/core/src/components/router/router-utils.ts
index 36e4815dae..1bc9cb5a51 100644
--- a/packages/core/src/components/router/router-utils.ts
+++ b/packages/core/src/components/router/router-utils.ts
@@ -1,5 +1,5 @@
export interface NavOutlet {
- setRouteId(id: any, data?: any): Promise;
+ setRouteId(id: any, data: any, direction: number): Promise;
getRouteId(): string;
getContentElement(): HTMLElement | null;
}
@@ -28,22 +28,24 @@ export class RouterSegments {
}
}
-export function writeNavState(root: HTMLElement, chain: RouterEntries, index = 0): Promise {
+export function writeNavState(root: HTMLElement, chain: RouterEntries, index: number, direction: number): Promise {
if (index >= chain.length) {
return Promise.resolve();
}
-
const route = chain[index];
const node = breadthFirstSearch(root);
if (!node) {
return Promise.resolve();
}
return node.componentOnReady()
- .then(() => node.setRouteId(route.id, route.props))
- .then(() => {
+ .then(() => node.setRouteId(route.id, route.props, direction))
+ .then(changed => {
+ if (changed) {
+ direction = 0;
+ }
const nextEl = node.getContentElement();
if (nextEl) {
- return writeNavState(nextEl, chain, index + 1);
+ return writeNavState(nextEl, chain, index + 1, direction);
}
return null;
});
@@ -199,18 +201,20 @@ export function breadthFirstSearch(root: HTMLElement): NavOutletElement | null {
return null;
}
-export function writePath(history: History, base: string, usePath: boolean, path: string[], isPop: boolean) {
+export function writePath(history: History, base: string, usePath: boolean, path: string[], isPop: boolean, state: number) {
path = [base, ...path];
let url = generatePath(path);
if (usePath) {
url = '#' + url;
}
+ state++;
if (isPop) {
history.back();
- history.replaceState(null, null, url);
+ history.replaceState(state, null, url);
} else {
- history.pushState(null, null, url);
+ 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/router/router.tsx b/packages/core/src/components/router/router.tsx
index 1f1de328cd..2929316bca 100644
--- a/packages/core/src/components/router/router.tsx
+++ b/packages/core/src/components/router/router.tsx
@@ -10,6 +10,7 @@ export class Router {
private routes: RouterEntries;
private busy = false;
+ private state = 0;
@Prop({ context: 'config' }) config: Config;
@Prop({ context: 'dom' }) dom: DomController;
@@ -30,8 +31,12 @@ export class Router {
});
}
- @Listen('window:hashchange')
+ @Listen('window:popstate')
protected onURLHashChanged() {
+ if (window.history.state === null) {
+ this.state++;
+ window.history.replaceState(this.state, document.title, document.location.href);
+ }
if (!this.busy) {
console.debug('[OUT] hash changed -> write nav state');
this.writeNavStateRoot();
@@ -43,35 +48,34 @@ export class Router {
if (this.busy) {
return;
}
-
console.debug('[IN] nav changed -> update URL');
const { stack, pivot } = this.readNavState();
- const { path, routes} = matchPath(stack, this.routes);
+ const { path, routes } = matchPath(stack, this.routes);
if (pivot) {
// readNavState() found a pivot that is not initialized
console.debug('[IN] pivot uninitialized -> write partial nav state');
- this.writeNavState(pivot, [], routes);
+ this.writeNavState(pivot, [], routes, 0);
}
const isPop = ev.detail.isPop === true;
this.writePath(path, isPop);
}
-
private writeNavStateRoot(): Promise {
const node = document.querySelector('ion-app') as HTMLElement;
const currentPath = this.readPath();
+ const direction = window.history.state >= this.state ? 1 : -1;
if (currentPath) {
- return this.writeNavState(node, currentPath, this.routes);
+ return this.writeNavState(node, currentPath, this.routes, direction);
}
return Promise.resolve();
}
- private writeNavState(node: any, path: string[], routes: RouterEntries): Promise {
+ private writeNavState(node: any, path: string[], routes: RouterEntries, direction: number): Promise {
const chain = matchRouteChain(path, routes);
this.busy = true;
- return writeNavState(node, chain)
+ return writeNavState(node, chain, 0, direction)
.catch(err => console.error(err))
.then(() => this.busy = false);
}
@@ -82,7 +86,7 @@ export class Router {
}
private writePath(path: string[], isPop: boolean) {
- writePath(window.history, this.base, this.useHash, path, isPop);
+ this.state = writePath(window.history, this.base, this.useHash, path, isPop, this.state);
}
private readPath(): string[] | null {
diff --git a/packages/core/src/components/router/test/basic/index.html b/packages/core/src/components/router/test/basic/index.html
index 2633b7a9e0..eb68becf89 100644
--- a/packages/core/src/components/router/test/basic/index.html
+++ b/packages/core/src/components/router/test/basic/index.html
@@ -14,12 +14,17 @@
+
+
+
-
+
+
+
@@ -43,7 +48,7 @@
title="Messages"
icon="chatboxes"
name="tab-four">
- INLINE CONTENT
+
diff --git a/packages/core/src/components/tab/tab.tsx b/packages/core/src/components/tab/tab.tsx
index 1ee4f0f7d0..0ecf1c60ee 100644
--- a/packages/core/src/components/tab/tab.tsx
+++ b/packages/core/src/components/tab/tab.tsx
@@ -8,7 +8,7 @@ import { FrameworkDelegate } from '../..';
})
export class Tab {
- // private loaded = false;
+ private loaded = false;
@Element() el: HTMLElement;
@State() init = false;
@@ -81,36 +81,12 @@ export class Tab {
@Method()
setActive(active: boolean): Promise {
this.active = active;
- if (active) {
- const nav = getNavAsChildIfExists(this.el);
- if (nav) {
- // the tab's nav has been initialized externally
-
- return ensureExternalRounterController().then((externalRouterController) => {
- if (externalRouterController.getExternalNavPromise()) {
- return (externalRouterController.getExternalNavPromise() as Promise).then(() => {
- externalRouterController.clearExternalNavPromise();
- });
- }
-
- // the tab's nav has not been initialized externally, so
- // check if we need to initiailize it
- return (nav as any).componentOnReady().then(() => {
- return nav.onAllTransitionsComplete();
- }).then(() => {
- if (!nav.getViews().length && !nav.isTransitioning() && !nav.initialized) {
- return nav.setRoot(nav.root);
- }
- return Promise.resolve();
- });
- });
- }
- }
-
- /*if (this.loaded || !active) {
+ if (!active) {
return Promise.resolve();
}
-
+ if (this.loaded) {
+ return this.configChildgNav();
+ }
this.loaded = true;
let promise: Promise;
@@ -122,9 +98,7 @@ export class Tab {
} else {
promise = Promise.resolve();
}
- return promise.then(() => this.fireChildren());
- */
- return Promise.resolve();
+ return promise.then(() => this.configChildgNav());
}
@Method()
@@ -138,16 +112,32 @@ export class Tab {
return null;
}
- /*private fireChildren() {
+ private configChildgNav(): Promise {
const nav = getNavAsChildIfExists(this.el);
- if (nav && nav.getViews().length === 0 && nav.root) {
- // we need to initialize
- return nav.setRoot(nav.root);
+ if (nav) {
+ // the tab's nav has been initialized externally
+ return ensureExternalRounterController().then((externalRouterController) => {
+ const externalNavPromise = externalRouterController.getExternalNavPromise();
+ if (externalNavPromise) {
+ return externalNavPromise.then(() => {
+ externalRouterController.clearExternalNavPromise();
+ });
+ }
+
+ // the tab's nav has not been initialized externally, so
+ // check if we need to initiailize it
+ return nav.componentOnReady()
+ .then(() => nav.onAllTransitionsComplete())
+ .then(() => {
+ if (nav.getViews().length === 0 && !nav.isTransitioning() && !nav.initialized) {
+ return nav.setRoot(nav.root);
+ }
+ return Promise.resolve();
+ });
+ });
}
- // it's already been initialized if it exists
return Promise.resolve();
}
- */
hostData() {
const visible = this.active && this.selected;
@@ -166,7 +156,7 @@ export class Tab {
}
}
-/*function attachViewToDom(container: HTMLElement, cmp: string): Promise {
+function attachViewToDom(container: HTMLElement, cmp: string): Promise {
const el = document.createElement(cmp) as HTMLStencilElement;
container.appendChild(el);
if (el.componentOnReady) {
@@ -174,4 +164,3 @@ export class Tab {
}
return Promise.resolve();
}
-*/
diff --git a/packages/core/src/components/tabs/tabs.tsx b/packages/core/src/components/tabs/tabs.tsx
index bbab8341c1..72ed8d1cec 100644
--- a/packages/core/src/components/tabs/tabs.tsx
+++ b/packages/core/src/components/tabs/tabs.tsx
@@ -160,12 +160,12 @@ export class Tabs implements NavOutlet {
}
@Method()
- setRouteId(id: any, _: any = {}): Promise {
- if (this.selectedTab === id) {
- return Promise.resolve();
+ setRouteId(id: any): Promise {
+ if (this.selectedTab && this.selectedTab.getRouteId() === id) {
+ return Promise.resolve(false);
}
const tab = this.tabs.find(t => id === t.getRouteId());
- return this.select(tab);
+ return this.select(tab).then(() => true);
}
@@ -185,13 +185,13 @@ export class Tabs implements NavOutlet {
private initTabs() {
const tabs = this.tabs = Array.from(this.el.querySelectorAll('ion-tab'));
- const tabPromises: Promise[] = [];
- for (const tab of tabs) {
+ const tabPromises = tabs.map(tab => {
const id = `t-${this.tabsId}-${++this.ids}`;
tab.btnId = 'tab-' + id;
tab.id = 'tabpanel-' + id;
- tabPromises.push((tab as any).componentOnReady());
- }
+ return tab.componentOnReady();
+ });
+
return Promise.all(tabPromises);
}