diff --git a/src/navigation/deep-linker.ts b/src/navigation/deep-linker.ts index 4ed2e23841..da76adcb07 100644 --- a/src/navigation/deep-linker.ts +++ b/src/navigation/deep-linker.ts @@ -10,26 +10,9 @@ import { Tabs } from '../components/tabs/tabs'; import { UrlSerializer } from './url-serializer'; import { ViewController } from './view-controller'; - -/** - * Deep Linking Scenarios: - * 1) Initialize all NavControllers using the initial browser URL - * 2) User clicks browser back button - * 3) User clicks browser forward button - * 4) User changes browser URL - * 5) User clicks link href - * 6) App uses NavController push/pop/setRoot/insert/remove - * - * Terms: - * - URL: The string value found in the browser's URL bar - * - Segment: Deep linker's data about each section between / in the URL - * - Path: Deep linker's array of segments - * - History: Deep linker's string array of internal URL history - * - Location: Angular's Location provider, which abstracts Hash/Path Location Strategies - */ - - /** + * @name DeepLinker + * @description * DeepLinker handles registering and displaying specific views based on URLs. It's used * underneath NavController so you'll never have to interact with it directly. When a new * view is push'ed with NavController, the URL is updated to match the path back to this @@ -45,35 +28,112 @@ import { ViewController } from './view-controller'; * Ionic developers to think of URLs as a breadcrumb rather than as the source of * truth in navigation. This encourages flexible navigation design and happy apps all * over the world. - */ - -/** - * @private * + * + * @usage + * + * DeepLinker can be used in the `IonicModule.forRoot` method, as the third parameter + * + * ```ts + * imports: [ + * IonicModule.forRoot(MyApp, {}, { + * links: [] + * }) + * ] + * ``` + * + * DeepLinker implements `DeepLinkerConfig`, which is an object with an array of links. + * So for basic example based on the blank starer, a link setup like so: + * + * ```ts + * imports: [ + * IonicModule.forRoot(MyApp, {}, { + * links: [ + * { component: HomePage, name: 'Home', segment: 'home' } + * ] + * }) + * ] + * ``` + * + * This Feels pretty familiar to how Angular sets up routes, but has some fundamental differences. + * Since components could be loaded anywhere in the app, DeepLinker lets you define their URL segment. + * So at any point, when a Component becomes the active view, we just append the URL segment. + * + * ### Dynamic Links + * + * Since passing data around is common practice in an app, we can reflect that in our app's URL in a similar manner to Angular's router. + * + * ```ts + * links: [ + * { component: HomePage, name: 'Home', segment: 'home' } + * { component: DetailPage, name: 'Detail', segment: 'detail/:user' } + * ] + * ``` + * This approach of using `:param` has been around in previous routing solutions. + * All this means is that when we push a new component on to the stack, in the navParams, there should be a property of `user`. + * The property needs to be something that can be serialized by the DeepLinker. + * So setting its value to be that of a string or number is suggested. + * + * So in a typical `navCtrl.push()` scenario, we'd do something like this: + * + * ```ts + * pushPage(userInfo) { + * this.navCtrl.push(DetailPage, { + * 'user': userInfo + * }) + * } + * ``` + * + * + * + * ### Default History + * + * In some cases when a page loads, you might be sent to a component that has it's own information, but not back view. + * This situation is common when loading a page from a Push Notification. + * If you want a component to have a default history when none is present, you can use the `defaultHistory` property + * + * The `defaultHistory` property takes an array of components to create the history stack if none exist. + * + * ```ts + * links: [ + * { component: HomePage, name: 'Home', segment: 'home' } + * { component: DetailPage, name: 'Detail', segment: 'detail/:user', defaultHistory: [HomePage] } + * ] + * ``` */ export class DeepLinker { + + /** + * @internal + */ segments: NavSegment[] = []; + /** + * @internal + */ history: string[] = []; + /** + * @internal + */ indexAliasUrl: string; - constructor(public app: App, public serializer: UrlSerializer, public location: Location) { } + constructor(public _app: App, public _serializer: UrlSerializer, public _location: Location) { } /** * @internal */ init() { // scenario 1: Initial load of all navs from the initial browser URL - const browserUrl = normalizeUrl(this.location.path()); + const browserUrl = normalizeUrl(this._location.path()); console.debug(`DeepLinker, init load: ${browserUrl}`); // 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 this.historyPush(browserUrl); // listen for browser URL changes - this.location.subscribe((locationChg: { url: string }) => { + this._location.subscribe((locationChg: { url: string }) => { this.urlChange(normalizeUrl(locationChg.url)); }); } @@ -102,7 +162,7 @@ export class DeepLinker { } // get the app's root nav - const appRootNav =