refactor(navigation): async component loading (aka lazy loading)

async component loading (aka lazy loading)
This commit is contained in:
Dan Bucholtz
2017-03-02 15:05:35 -06:00
parent e40590d68c
commit 96657535f1
6 changed files with 204 additions and 140 deletions

View File

@ -1,7 +1,9 @@
import { ComponentFactory, ComponentFactoryResolver } from '@angular/core';
import { Location } from '@angular/common'; import { Location } from '@angular/common';
import { App } from '../components/app/app'; import { App } from '../components/app/app';
import { convertToViews, isNav, isTab, isTabs, NavSegment, DIRECTION_BACK } from './nav-util'; import { convertToViews, isNav, isTab, isTabs, NavLink, NavSegment, DIRECTION_BACK } from './nav-util';
import { ModuleLoader } from '../util/module-loader';
import { isArray, isPresent } from '../util/util'; import { isArray, isPresent } from '../util/util';
import { Nav } from '../components/nav/nav'; import { Nav } from '../components/nav/nav';
import { NavController } from './nav-controller'; import { NavController } from './nav-controller';
@ -117,20 +119,23 @@ import { ViewController } from './view-controller';
*/ */
export class DeepLinker { export class DeepLinker {
/** /** @internal */
* @internal _segments: NavSegment[] = [];
*/ /** @internal */
segments: NavSegment[] = []; _history: string[] = [];
/** /** @internal */
* @internal _indexAliasUrl: string;
*/ /** @internal */
history: string[] = []; _cfrMap = new Map<any, ComponentFactoryResolver>();
/**
* @internal
*/
indexAliasUrl: string;
constructor(public _app: App, public _serializer: UrlSerializer, public _location: Location) { }
constructor(
public _app: App,
public _serializer: UrlSerializer,
public _location: Location,
public _moduleLoader: ModuleLoader,
public _baseCfr: ComponentFactoryResolver
) {}
/** /**
* @internal * @internal
@ -141,14 +146,14 @@ export class DeepLinker {
console.debug(`DeepLinker, init load: ${browserUrl}`); console.debug(`DeepLinker, init load: ${browserUrl}`);
// update the Path from the browser URL // update the Path from the browser URL
this.segments = this._serializer.parse(browserUrl); this._segments = this._serializer.parse(browserUrl);
// remember this URL in our internal history stack // remember this URL in our internal history stack
this.historyPush(browserUrl); this._historyPush(browserUrl);
// listen for browser URL changes // listen for browser URL changes
this._location.subscribe((locationChg: { url: string }) => { this._location.subscribe((locationChg: { url: string }) => {
this.urlChange(normalizeUrl(locationChg.url)); this._urlChange(normalizeUrl(locationChg.url));
}); });
} }
@ -156,23 +161,23 @@ export class DeepLinker {
* The browser's location has been updated somehow. * The browser's location has been updated somehow.
* @internal * @internal
*/ */
urlChange(browserUrl: string) { _urlChange(browserUrl: string) {
// do nothing if this url is the same as the current one // do nothing if this url is the same as the current one
if (!this.isCurrentUrl(browserUrl)) { if (!this._isCurrentUrl(browserUrl)) {
if (this.isBackUrl(browserUrl)) { if (this._isBackUrl(browserUrl)) {
// scenario 2: user clicked the browser back button // scenario 2: user clicked the browser back button
// scenario 4: user changed the browser URL to what was the back url was // scenario 4: user changed the browser URL to what was the back url was
// scenario 5: user clicked a link href that was the back url // scenario 5: user clicked a link href that was the back url
console.debug(`DeepLinker, browser urlChange, back to: ${browserUrl}`); console.debug(`DeepLinker, browser urlChange, back to: ${browserUrl}`);
this.historyPop(); this._historyPop();
} else { } else {
// scenario 3: user click forward button // scenario 3: user click forward button
// scenario 4: user changed browser URL that wasn't the back url // scenario 4: user changed browser URL that wasn't the back url
// scenario 5: user clicked a link href that wasn't the back url // scenario 5: user clicked a link href that wasn't the back url
console.debug(`DeepLinker, browser urlChange, forward to: ${browserUrl}`); console.debug(`DeepLinker, browser urlChange, forward to: ${browserUrl}`);
this.historyPush(browserUrl); this._historyPush(browserUrl);
} }
// get the app's root nav // get the app's root nav
@ -180,10 +185,10 @@ export class DeepLinker {
if (appRootNav) { if (appRootNav) {
if (browserUrl === '/') { if (browserUrl === '/') {
// a url change to the index url // a url change to the index url
if (isPresent(this.indexAliasUrl)) { if (isPresent(this._indexAliasUrl)) {
// we already know the indexAliasUrl // we already know the indexAliasUrl
// update the url to use the know alias // update the url to use the know alias
browserUrl = this.indexAliasUrl; browserUrl = this._indexAliasUrl;
} else { } else {
// the url change is to the root but we don't // the url change is to the root but we don't
@ -198,8 +203,8 @@ export class DeepLinker {
} }
// normal url // normal url
this.segments = this._serializer.parse(browserUrl); this._segments = this._serializer.parse(browserUrl);
this.loadNavFromPath(appRootNav); this._loadNavFromPath(appRootNav);
} }
} }
} }
@ -216,13 +221,13 @@ export class DeepLinker {
if (activeNav) { if (activeNav) {
// build up the segments of all the navs from the lowest level // build up the segments of all the navs from the lowest level
this.segments = this.pathFromNavs(activeNav); this._segments = this._pathFromNavs(activeNav);
// build a string URL out of the Path // build a string URL out of the Path
const browserUrl = this._serializer.serialize(this.segments); const browserUrl = this._serializer.serialize(this._segments);
// update the browser's location // update the browser's location
this.updateLocation(browserUrl, direction); this._updateLocation(browserUrl, direction);
} }
} }
} }
@ -230,35 +235,70 @@ export class DeepLinker {
/** /**
* @internal * @internal
*/ */
updateLocation(browserUrl: string, direction: string) { _updateLocation(browserUrl: string, direction: string) {
if (this.indexAliasUrl === browserUrl) { if (this._indexAliasUrl === browserUrl) {
browserUrl = '/'; browserUrl = '/';
} }
if (direction === DIRECTION_BACK && this.isBackUrl(browserUrl)) { if (direction === DIRECTION_BACK && this._isBackUrl(browserUrl)) {
// this URL is exactly the same as the back URL // this URL is exactly the same as the back URL
// it's safe to use the browser's location.back() // it's safe to use the browser's location.back()
console.debug(`DeepLinker, location.back(), url: '${browserUrl}'`); console.debug(`DeepLinker, location.back(), url: '${browserUrl}'`);
this.historyPop(); this._historyPop();
this._location.back(); this._location.back();
} else if (!this.isCurrentUrl(browserUrl)) { } else if (!this._isCurrentUrl(browserUrl)) {
// probably navigating forward // probably navigating forward
console.debug(`DeepLinker, location.go('${browserUrl}')`); console.debug(`DeepLinker, location.go('${browserUrl}')`);
this.historyPush(browserUrl); this._historyPush(browserUrl);
this._location.go(browserUrl); this._location.go(browserUrl);
} }
} }
getComponentFromName(componentName: string): Promise<any> {
const link = this._serializer.getLinkFromName(componentName);
if (link) {
// cool, we found the right link for this component name
return this.getNavLinkComponent(link);
}
// umm, idk
return Promise.reject(`invalid link: ${componentName}`);
}
getNavLinkComponent(link: NavLink) {
if (link.component) {
// sweet, we're already got a component loaded for this link
return Promise.resolve(link.component);
}
if (link.loadChildren) {
// awesome, looks like we'll lazy load this component
// using loadChildren as the URL to request
return this._moduleLoader.load(link.loadChildren).then(loadedModule => {
// kerpow!! we just lazy loaded a component!!
// update the existing link with the loaded component
link.component = loadedModule.component;
this._cfrMap.set(link.component, loadedModule.componentFactoryResolver);
return link.component;
});
}
return Promise.reject(`invalid link component: ${link.name}`);
}
/** /**
* @internal * @internal
*/ */
getComponentFromName(componentName: any): any { resolveComponent(component: any): ComponentFactory<any> {
const segment = this._serializer.createSegmentFromName(componentName); let cfr = this._cfrMap.get(component);
if (segment && segment.component) { if (!cfr) {
return segment.component; cfr = this._baseCfr;
} }
return null; return cfr.resolveComponentFactory(component);
} }
/** /**
@ -268,7 +308,7 @@ export class DeepLinker {
// create a segment out of just the passed in name // create a segment out of just the passed in name
const segment = this._serializer.createSegmentFromName(nameOrComponent); const segment = this._serializer.createSegmentFromName(nameOrComponent);
if (segment) { if (segment) {
const path = this.pathFromNavs(nav, segment.component, data); const path = this._pathFromNavs(nav, segment.component, data);
// serialize the segments into a browser URL // serialize the segments into a browser URL
// and prepare the URL with the location and return // and prepare the URL with the location and return
const url = this._serializer.serialize(path); const url = this._serializer.serialize(path);
@ -284,7 +324,7 @@ export class DeepLinker {
* *
* @internal * @internal
*/ */
pathFromNavs(nav: NavController, component?: any, data?: any): NavSegment[] { _pathFromNavs(nav: NavController, component?: any, data?: any): NavSegment[] {
const segments: NavSegment[] = []; const segments: NavSegment[] = [];
let view: ViewController; let view: ViewController;
let segment: NavSegment; let segment: NavSegment;
@ -321,7 +361,7 @@ export class DeepLinker {
if (isTab(nav)) { if (isTab(nav)) {
// this nav is a Tab, which is a child of Tabs // this nav is a Tab, which is a child of Tabs
// add a segment to represent which Tab is the selected one // add a segment to represent which Tab is the selected one
tabSelector = this.getTabSelector(<any>nav); tabSelector = this._getTabSelector(<any>nav);
segments.push({ segments.push({
id: tabSelector, id: tabSelector,
name: tabSelector, name: tabSelector,
@ -347,7 +387,7 @@ export class DeepLinker {
/** /**
* @internal * @internal
*/ */
getTabSelector(tab: Tab): string { _getTabSelector(tab: Tab): string {
if (isPresent(tab.tabUrlPath)) { if (isPresent(tab.tabUrlPath)) {
return tab.tabUrlPath; return tab.tabUrlPath;
} }
@ -385,7 +425,7 @@ export class DeepLinker {
* @internal * @internal
*/ */
initNav(nav: any): NavSegment { initNav(nav: any): NavSegment {
const path = this.segments; const path = this._segments;
if (nav && path.length) { if (nav && path.length) {
if (!nav.parent) { if (!nav.parent) {
@ -408,22 +448,18 @@ export class DeepLinker {
/** /**
* @internal * @internal
*/ */
initViews(segment: NavSegment): ViewController[] { initViews(segment: NavSegment) {
let views: ViewController[];
if (isArray(segment.defaultHistory)) {
views = convertToViews(this, segment.defaultHistory);
} else {
views = [];
}
const view = new ViewController(segment.component, segment.data); const view = new ViewController(segment.component, segment.data);
view.id = segment.id; view.id = segment.id;
views.push(view); if (isArray(segment.defaultHistory)) {
return convertToViews(this, segment.defaultHistory).then(views => {
views.push(view);
return views;
});
}
return views; return Promise.resolve([view]);
} }
/** /**
@ -436,13 +472,13 @@ export class DeepLinker {
* *
* @internal * @internal
*/ */
loadNavFromPath(nav: NavController, done?: Function) { _loadNavFromPath(nav: NavController, done?: Function) {
if (!nav) { if (!nav) {
done && done(); done && done();
} else { } else {
this.loadViewFromSegment(nav, () => { this._loadViewFromSegment(nav, () => {
this.loadNavFromPath(nav.getActiveChildNav(), done); this._loadNavFromPath(nav.getActiveChildNav(), done);
}); });
} }
} }
@ -450,7 +486,7 @@ export class DeepLinker {
/** /**
* @internal * @internal
*/ */
loadViewFromSegment(navInstance: any, done: Function) { _loadViewFromSegment(navInstance: any, done: Function) {
// load up which nav ids belong to its nav segment // load up which nav ids belong to its nav segment
let segment = this.initNav(navInstance); let segment = this.initNav(navInstance);
if (!segment) { if (!segment) {
@ -509,25 +545,25 @@ export class DeepLinker {
/** /**
* @internal * @internal
*/ */
isBackUrl(browserUrl: string) { _isBackUrl(browserUrl: string) {
return (browserUrl === this.history[this.history.length - 2]); return (browserUrl === this._history[this._history.length - 2]);
} }
/** /**
* @internal * @internal
*/ */
isCurrentUrl(browserUrl: string) { _isCurrentUrl(browserUrl: string) {
return (browserUrl === this.history[this.history.length - 1]); return (browserUrl === this._history[this._history.length - 1]);
} }
/** /**
* @internal * @internal
*/ */
historyPush(browserUrl: string) { _historyPush(browserUrl: string) {
if (!this.isCurrentUrl(browserUrl)) { if (!this._isCurrentUrl(browserUrl)) {
this.history.push(browserUrl); this._history.push(browserUrl);
if (this.history.length > 30) { if (this._history.length > 30) {
this.history.shift(); this._history.shift();
} }
} }
} }
@ -535,18 +571,18 @@ export class DeepLinker {
/** /**
* @internal * @internal
*/ */
historyPop() { _historyPop() {
this.history.pop(); this._history.pop();
if (!this.history.length) { if (!this._history.length) {
this.historyPush(this._location.path()); this._historyPush(this._location.path());
} }
} }
} }
export function setupDeepLinker(app: App, serializer: UrlSerializer, location: Location) { export function setupDeepLinker(app: App, serializer: UrlSerializer, location: Location, moduleLoader: ModuleLoader, cfr: ComponentFactoryResolver) {
const deepLinker = new DeepLinker(app, serializer, location); const deepLinker = new DeepLinker(app, serializer, location, moduleLoader, cfr);
deepLinker.init(); deepLinker.init();
return deepLinker; return deepLinker;
} }

View File

@ -4,7 +4,7 @@ import { AnimationOptions } from '../animations/animation';
import { App } from '../components/app/app'; import { App } from '../components/app/app';
import { Config } from '../config/config'; import { Config } from '../config/config';
import { convertToView, convertToViews, NavOptions, DIRECTION_BACK, DIRECTION_FORWARD, INIT_ZINDEX, import { convertToView, convertToViews, NavOptions, DIRECTION_BACK, DIRECTION_FORWARD, INIT_ZINDEX,
TransitionResolveFn, TransitionInstruction, ViewState } from './nav-util'; TransitionResolveFn, TransitionInstruction, STATE_INITIALIZED, STATE_LOADED, STATE_PRE_RENDERED } from './nav-util';
import { setZIndex } from './nav-util'; import { setZIndex } from './nav-util';
import { DeepLinker } from './deep-linker'; import { DeepLinker } from './deep-linker';
import { DomController } from '../platform/dom-controller'; import { DomController } from '../platform/dom-controller';
@ -72,27 +72,36 @@ export class NavControllerBase extends Ion implements NavController {
} }
push(page: any, params?: any, opts?: NavOptions, done?: Function): Promise<any> { push(page: any, params?: any, opts?: NavOptions, done?: Function): Promise<any> {
return this._queueTrns({ return convertToView(this._linker, page, params).then(viewController => {
insertStart: -1, return this._queueTrns({
insertViews: [convertToView(this._linker, page, params)], insertStart: -1,
opts: opts, insertViews: [viewController],
}, done); opts: opts,
}, done);
}).catch((err: Error) => {
console.error('Failed to navigate: ', err.message);
throw err;
});
} }
insert(insertIndex: number, page: any, params?: any, opts?: NavOptions, done?: Function): Promise<any> { insert(insertIndex: number, page: any, params?: any, opts?: NavOptions, done?: Function): Promise<any> {
return this._queueTrns({ return convertToView(this._linker, page, params).then(viewController => {
insertStart: insertIndex, return this._queueTrns({
insertViews: [convertToView(this._linker, page, params)], insertStart: insertIndex,
opts: opts, insertViews: [viewController],
}, done); opts: opts,
}, done);
});
} }
insertPages(insertIndex: number, insertPages: any[], opts?: NavOptions, done?: Function): Promise<any> { insertPages(insertIndex: number, insertPages: any[], opts?: NavOptions, done?: Function): Promise<any> {
return this._queueTrns({ return convertToViews(this._linker, insertPages).then(viewControllers => {
insertStart: insertIndex, return this._queueTrns({
insertViews: convertToViews(this._linker, insertPages), insertStart: insertIndex,
opts: opts, insertViews: viewControllers,
}, done); opts: opts,
}, done);
});
} }
pop(opts?: NavOptions, done?: Function): Promise<any> { pop(opts?: NavOptions, done?: Function): Promise<any> {
@ -152,13 +161,15 @@ export class NavControllerBase extends Ion implements NavController {
} }
setRoot(pageOrViewCtrl: any, params?: any, opts?: NavOptions, done?: Function): Promise<any> { setRoot(pageOrViewCtrl: any, params?: any, opts?: NavOptions, done?: Function): Promise<any> {
const viewControllers = [convertToView(this._linker, pageOrViewCtrl, params)]; return convertToView(this._linker, pageOrViewCtrl, params).then((viewController) => {
return this._setPages(viewControllers, opts, done); return this._setPages([viewController], opts, done);
});
} }
setPages(pages: any[], opts?: NavOptions, done?: Function): Promise<any> { setPages(pages: any[], opts?: NavOptions, done?: Function): Promise<any> {
const viewControllers = convertToViews(this._linker, pages); return convertToViews(this._linker, pages).then(viewControllers => {
return this._setPages(viewControllers, opts, done); return this._setPages(viewControllers, opts, done);
});
} }
_setPages(viewControllers: ViewController[], opts?: NavOptions, done?: Function): Promise<any> { _setPages(viewControllers: ViewController[], opts?: NavOptions, done?: Function): Promise<any> {
@ -220,7 +231,7 @@ export class NavControllerBase extends Ion implements NavController {
this._queue.length = 0; this._queue.length = 0;
while (trns) { while (trns) {
if (trns.enteringView && (trns.enteringView._state !== ViewState.LOADED)) { if (trns.enteringView && (trns.enteringView._state !== STATE_LOADED)) {
// destroy the entering views and all of their hopes and dreams // destroy the entering views and all of their hopes and dreams
this._destroyView(trns.enteringView); this._destroyView(trns.enteringView);
} }
@ -483,17 +494,17 @@ export class NavControllerBase extends Ion implements NavController {
{ provide: ViewController, useValue: enteringView }, { provide: ViewController, useValue: enteringView },
{ provide: NavParams, useValue: enteringView.getNavParams() } { provide: NavParams, useValue: enteringView.getNavParams() }
]); ]);
const componentFactory = this._cfr.resolveComponentFactory(enteringView.component); const componentFactory = this._linker.resolveComponent(enteringView.component);
const childInjector = ReflectiveInjector.fromResolvedProviders(componentProviders, this._viewport.parentInjector); const childInjector = ReflectiveInjector.fromResolvedProviders(componentProviders, this._viewport.parentInjector);
// create ComponentRef and set it to the entering view // create ComponentRef and set it to the entering view
enteringView.init(componentFactory.create(childInjector, [])); enteringView.init(componentFactory.create(childInjector, []));
enteringView._state = ViewState.INITIALIZED; enteringView._state = STATE_INITIALIZED;
this._preLoad(enteringView); this._preLoad(enteringView);
} }
_viewAttachToDOM(view: ViewController, componentRef: ComponentRef<any>, viewport: ViewContainerRef) { _viewAttachToDOM(view: ViewController, componentRef: ComponentRef<any>, viewport: ViewContainerRef) {
assert(view._state === ViewState.INITIALIZED, 'view state must be INITIALIZED'); assert(view._state === STATE_INITIALIZED, 'view state must be INITIALIZED');
// fire willLoad before change detection runs // fire willLoad before change detection runs
this._willLoad(view); this._willLoad(view);
@ -501,7 +512,7 @@ export class NavControllerBase extends Ion implements NavController {
// render the component ref instance to the DOM // render the component ref instance to the DOM
// ******** DOM WRITE **************** // ******** DOM WRITE ****************
viewport.insert(componentRef.hostView, viewport.length); viewport.insert(componentRef.hostView, viewport.length);
view._state = ViewState.PRE_RENDERED; view._state = STATE_PRE_RENDERED;
if (view._cssClass) { if (view._cssClass) {
// the ElementRef of the actual ion-page created // the ElementRef of the actual ion-page created
@ -604,7 +615,7 @@ export class NavControllerBase extends Ion implements NavController {
} }
}); });
if (enteringView && enteringView._state === ViewState.INITIALIZED) { if (enteringView && enteringView._state === STATE_INITIALIZED) {
// render the entering component in the DOM // render the entering component in the DOM
// this would also render new child navs/views // this would also render new child navs/views
// which may have their very own async canEnter/Leave tests // which may have their very own async canEnter/Leave tests

View File

@ -7,33 +7,38 @@ import { NavControllerBase } from './nav-controller-base';
import { Transition } from '../transitions/transition'; import { Transition } from '../transitions/transition';
export function getComponent(linker: DeepLinker, nameOrPageOrView: any): any { export function getComponent(linker: DeepLinker, nameOrPageOrView: any, params?: any) {
if (typeof nameOrPageOrView === 'function') { if (typeof nameOrPageOrView === 'function') {
return nameOrPageOrView; return Promise.resolve(
new ViewController(nameOrPageOrView, params)
);
} }
if (typeof nameOrPageOrView === 'string') { if (typeof nameOrPageOrView === 'string') {
return linker.getComponentFromName(nameOrPageOrView); return linker.getComponentFromName(nameOrPageOrView).then((component) => {
return new ViewController(component, params);
});
} }
return null;
return Promise.resolve(null);
} }
export function convertToView(linker: DeepLinker, nameOrPageOrView: any, params: any): ViewController { export function convertToView(linker: DeepLinker, nameOrPageOrView: any, params: any) {
if (nameOrPageOrView) { if (nameOrPageOrView) {
if (isViewController(nameOrPageOrView)) { if (isViewController(nameOrPageOrView)) {
// is already a ViewController // is already a ViewController
return nameOrPageOrView; return Promise.resolve(<ViewController>nameOrPageOrView);
}
let component = getComponent(linker, nameOrPageOrView);
if (component) {
return new ViewController(component, params);
} }
return getComponent(linker, nameOrPageOrView, params);
} }
console.error(`invalid page component: ${nameOrPageOrView}`); console.error(`invalid page component: ${nameOrPageOrView}`);
return null; return Promise.resolve(null);
} }
export function convertToViews(linker: DeepLinker, pages: any[]): ViewController[] { export function convertToViews(linker: DeepLinker, pages: any[]) {
const views: ViewController[] = []; const views: Promise<ViewController>[] = [];
if (isArray(pages)) { if (isArray(pages)) {
for (var i = 0; i < pages.length; i++) { for (var i = 0; i < pages.length; i++) {
var page = pages[i]; var page = pages[i];
@ -50,7 +55,7 @@ export function convertToViews(linker: DeepLinker, pages: any[]): ViewController
} }
} }
} }
return views; return Promise.all(views);
} }
let portalZindex = 9999; let portalZindex = 9999;
@ -98,19 +103,21 @@ export function isNav(nav: any): boolean {
// public link interface // public link interface
export interface DeepLinkMetadataType { export interface DeepLinkMetadataType {
name: string; name?: string;
segment?: string; segment?: string;
defaultHistory?: any[]; defaultHistory?: string[];
} }
/** /**
* @private * @private
*/ */
export class DeepLinkMetadata implements DeepLinkMetadataType { export class DeepLinkMetadata implements DeepLinkMetadataType {
component: any; component?: any;
name: string; viewFactoryFunction?: string;
loadChildren?: string;
name?: string;
segment?: string; segment?: string;
defaultHistory?: any[]; defaultHistory?: string[];
} }
export interface DeepLinkDecorator extends TypeDecorator {} export interface DeepLinkDecorator extends TypeDecorator {}
@ -134,7 +141,8 @@ export interface DeepLinkConfig {
// internal link interface, not exposed publicly // internal link interface, not exposed publicly
export interface NavLink { export interface NavLink {
component: any; component?: any;
loadChildren?: string;
name?: string; name?: string;
segment?: string; segment?: string;
parts?: string[]; parts?: string[];
@ -148,7 +156,8 @@ export interface NavLink {
export interface NavSegment { export interface NavSegment {
id: string; id: string;
name: string; name: string;
component: any; component?: any;
loadChildren?: string;
data: any; data: any;
navId?: string; navId?: string;
defaultHistory?: NavSegment[]; defaultHistory?: NavSegment[];
@ -192,11 +201,10 @@ export interface TransitionInstruction {
requiresTransition?: boolean; requiresTransition?: boolean;
} }
export enum ViewState {
INITIALIZED, export const STATE_INITIALIZED = 1;
PRE_RENDERED, export const STATE_PRE_RENDERED = 2;
LOADED, export const STATE_LOADED = 3;
}
export const INIT_ZINDEX = 100; export const INIT_ZINDEX = 100;

View File

@ -1,6 +1,6 @@
import { swipeShouldReset } from '../util/util'; import { swipeShouldReset } from '../util/util';
import { DomController } from '../platform/dom-controller'; import { DomController } from '../platform/dom-controller';
import { GestureController, GesturePriority, GESTURE_GO_BACK_SWIPE } from '../gestures/gesture-controller'; import { GestureController, GESTURE_PRIORITY_GO_BACK_SWIPE, GESTURE_GO_BACK_SWIPE } from '../gestures/gesture-controller';
import { NavControllerBase } from './nav-controller-base'; import { NavControllerBase } from './nav-controller-base';
import { Platform } from '../platform/platform'; import { Platform } from '../platform/platform';
import { SlideData } from '../gestures/slide-gesture'; import { SlideData } from '../gestures/slide-gesture';
@ -26,7 +26,7 @@ export class SwipeBackGesture extends SlideEdgeGesture {
domController: domCtrl, domController: domCtrl,
gesture: gestureCtlr.createGesture({ gesture: gestureCtlr.createGesture({
name: GESTURE_GO_BACK_SWIPE, name: GESTURE_GO_BACK_SWIPE,
priority: GesturePriority.GoBackSwipe, priority: GESTURE_PRIORITY_GO_BACK_SWIPE,
disableScroll: true disableScroll: true
}) })
}); });

View File

@ -35,21 +35,25 @@ export class UrlSerializer {
} }
createSegmentFromName(nameOrComponent: any): NavSegment { createSegmentFromName(nameOrComponent: any): NavSegment {
const configLink = this.links.find((link: NavLink) => { const configLink = this.getLinkFromName(nameOrComponent);
return (link.component === nameOrComponent) ||
(link.name === nameOrComponent) ||
(link.component.name === nameOrComponent);
});
return configLink ? { return configLink ? {
id: configLink.name, id: configLink.name,
name: configLink.name, name: configLink.name,
component: configLink.component, component: configLink.component,
loadChildren: configLink.loadChildren,
data: null, data: null,
defaultHistory: configLink.defaultHistory defaultHistory: configLink.defaultHistory
} : null; } : null;
} }
getLinkFromName(nameOrComponent: any) {
return this.links.find(link => {
return (link.component === nameOrComponent) ||
(link.name === nameOrComponent);
});
}
/** /**
* Serialize a path, which is made up of multiple NavSegments, * Serialize a path, which is made up of multiple NavSegments,
* into a URL string. Turn each segment into a string and concat them to a URL. * into a URL string. Turn each segment into a string and concat them to a URL.
@ -65,13 +69,14 @@ export class UrlSerializer {
if (component) { if (component) {
const link = findLinkByComponentData(this.links, component, data); const link = findLinkByComponentData(this.links, component, data);
if (link) { if (link) {
return this.createSegment(link, data); return this._createSegment(link, data);
} }
} }
return null; return null;
} }
createSegment(configLink: NavLink, data: any): NavSegment { /** @internal */
_createSegment(configLink: NavLink, data: any): NavSegment {
let urlParts = configLink.parts; let urlParts = configLink.parts;
if (isPresent(data)) { if (isPresent(data)) {
@ -101,6 +106,7 @@ export class UrlSerializer {
id: urlParts.join('/'), id: urlParts.join('/'),
name: configLink.name, name: configLink.name,
component: configLink.component, component: configLink.component,
loadChildren: configLink.loadChildren,
data: data, data: data,
defaultHistory: configLink.defaultHistory defaultHistory: configLink.defaultHistory
}; };
@ -151,6 +157,7 @@ export const parseUrlParts = (urlParts: string[], configLinks: NavLink[]): NavSe
id: urlParts[i], id: urlParts[i],
name: urlParts[i], name: urlParts[i],
component: null, component: null,
loadChildren: null,
data: null data: null
}; };
} }
@ -181,6 +188,7 @@ export const fillMatchedUrlParts = (segments: NavSegment[], urlParts: string[],
id: matchedUrlParts.join('/'), id: matchedUrlParts.join('/'),
name: configLink.name, name: configLink.name,
component: configLink.component, component: configLink.component,
loadChildren: configLink.loadChildren,
data: createMatchedData(matchedUrlParts, configLink), data: createMatchedData(matchedUrlParts, configLink),
defaultHistory: configLink.defaultHistory defaultHistory: configLink.defaultHistory
}; };

View File

@ -1,10 +1,11 @@
import { ComponentRef, ElementRef, EventEmitter, Output, Renderer } from '@angular/core'; import { ComponentRef, ElementRef, EventEmitter, Output, Renderer } from '@angular/core';
import { Footer, Header } from '../components/toolbar/toolbar'; import { Footer } from '../components/toolbar/toolbar-footer';
import { Header } from '../components/toolbar/toolbar-header';
import { isPresent } from '../util/util'; import { isPresent } from '../util/util';
import { Navbar } from '../components/navbar/navbar'; import { Navbar } from '../components/navbar/navbar';
import { NavController } from './nav-controller'; import { NavController } from './nav-controller';
import { NavOptions, ViewState } from './nav-util'; import { NavOptions } from './nav-util';
import { NavParams } from './nav-params'; import { NavParams } from './nav-params';
import { Content } from '../components/content/content'; import { Content } from '../components/content/content';
@ -46,7 +47,7 @@ export class ViewController {
_cmp: ComponentRef<any>; _cmp: ComponentRef<any>;
_nav: NavController; _nav: NavController;
_zIndex: number; _zIndex: number;
_state: ViewState; _state: number;
_cssClass: string; _cssClass: string;
/** /**