chore: router move-only
This commit is contained in:
@@ -0,0 +1 @@
|
||||
export * from './router';
|
||||
@@ -0,0 +1,83 @@
|
||||
import {Directive} from '@angular/core';
|
||||
import {Location} from '@angular/common';
|
||||
import {isString} from '../../src/facade/lang';
|
||||
import {Router} from '../router';
|
||||
import {Instruction} from '../instruction';
|
||||
|
||||
/**
|
||||
* The RouterLink directive lets you link to specific parts of your app.
|
||||
*
|
||||
* Consider the following route configuration:
|
||||
|
||||
* ```
|
||||
* @RouteConfig([
|
||||
* { path: '/user', component: UserCmp, as: 'User' }
|
||||
* ]);
|
||||
* class MyComp {}
|
||||
* ```
|
||||
*
|
||||
* When linking to this `User` route, you can write:
|
||||
*
|
||||
* ```
|
||||
* <a [routerLink]="['./User']">link to user component</a>
|
||||
* ```
|
||||
*
|
||||
* RouterLink expects the value to be an array of route names, followed by the params
|
||||
* for that level of routing. For instance `['/Team', {teamId: 1}, 'User', {userId: 2}]`
|
||||
* means that we want to generate a link for the `Team` route with params `{teamId: 1}`,
|
||||
* and with a child route `User` with params `{userId: 2}`.
|
||||
*
|
||||
* The first route name should be prepended with `/`, `./`, or `../`.
|
||||
* If the route begins with `/`, the router will look up the route from the root of the app.
|
||||
* If the route begins with `./`, the router will instead look in the current component's
|
||||
* children for the route. And if the route begins with `../`, the router will look at the
|
||||
* current component's parent.
|
||||
*/
|
||||
@Directive({
|
||||
selector: '[routerLink]',
|
||||
inputs: ['routeParams: routerLink', 'target: target'],
|
||||
host: {
|
||||
'(click)': 'onClick()',
|
||||
'[attr.href]': 'visibleHref',
|
||||
'[class.router-link-active]': 'isRouteActive'
|
||||
}
|
||||
})
|
||||
export class RouterLink {
|
||||
private _routeParams: any[];
|
||||
|
||||
// the url displayed on the anchor element.
|
||||
visibleHref: string;
|
||||
target: string;
|
||||
|
||||
// the instruction passed to the router to navigate
|
||||
private _navigationInstruction: Instruction;
|
||||
|
||||
constructor(private _router: Router, private _location: Location) {
|
||||
// we need to update the link whenever a route changes to account for aux routes
|
||||
this._router.subscribe((_) => this._updateLink());
|
||||
}
|
||||
|
||||
// because auxiliary links take existing primary and auxiliary routes into account,
|
||||
// we need to update the link whenever params or other routes change.
|
||||
private _updateLink(): void {
|
||||
this._navigationInstruction = this._router.generate(this._routeParams);
|
||||
var navigationHref = this._navigationInstruction.toLinkUrl();
|
||||
this.visibleHref = this._location.prepareExternalUrl(navigationHref);
|
||||
}
|
||||
|
||||
get isRouteActive(): boolean { return this._router.isRouteActive(this._navigationInstruction); }
|
||||
|
||||
set routeParams(changes: any[]) {
|
||||
this._routeParams = changes;
|
||||
this._updateLink();
|
||||
}
|
||||
|
||||
onClick(): boolean {
|
||||
// If no target, or if target is _self, prevent default browser behavior
|
||||
if (!isString(this.target) || this.target == '_self') {
|
||||
this._router.navigateByInstruction(this._navigationInstruction);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
import {PromiseWrapper, EventEmitter} from '../../src/facade/async';
|
||||
import {StringMapWrapper} from '../../src/facade/collection';
|
||||
import {isBlank, isPresent} from '../../src/facade/lang';
|
||||
import {
|
||||
Directive,
|
||||
Attribute,
|
||||
DynamicComponentLoader,
|
||||
ComponentRef,
|
||||
ViewContainerRef,
|
||||
provide,
|
||||
ReflectiveInjector,
|
||||
OnDestroy,
|
||||
Output
|
||||
} from '@angular/core';
|
||||
import * as routerMod from '../router';
|
||||
import {ComponentInstruction, RouteParams, RouteData} from '../instruction';
|
||||
import * as hookMod from '../lifecycle/lifecycle_annotations';
|
||||
import {hasLifecycleHook} from '../lifecycle/route_lifecycle_reflector';
|
||||
import {OnActivate, CanReuse, OnReuse, OnDeactivate, CanDeactivate} from '../interfaces';
|
||||
|
||||
let _resolveToTrue = PromiseWrapper.resolve(true);
|
||||
|
||||
/**
|
||||
* A router outlet is a placeholder that Angular dynamically fills based on the application's route.
|
||||
*
|
||||
* ## Use
|
||||
*
|
||||
* ```
|
||||
* <router-outlet></router-outlet>
|
||||
* ```
|
||||
*/
|
||||
@Directive({selector: 'router-outlet'})
|
||||
export class RouterOutlet implements OnDestroy {
|
||||
name: string = null;
|
||||
private _componentRef: Promise<ComponentRef<any>> = null;
|
||||
private _currentInstruction: ComponentInstruction = null;
|
||||
|
||||
@Output('activate') public activateEvents = new EventEmitter<any>();
|
||||
|
||||
constructor(private _viewContainerRef: ViewContainerRef, private _loader: DynamicComponentLoader,
|
||||
private _parentRouter: routerMod.Router, @Attribute('name') nameAttr: string) {
|
||||
if (isPresent(nameAttr)) {
|
||||
this.name = nameAttr;
|
||||
this._parentRouter.registerAuxOutlet(this);
|
||||
} else {
|
||||
this._parentRouter.registerPrimaryOutlet(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the Router to instantiate a new component during the commit phase of a navigation.
|
||||
* This method in turn is responsible for calling the `routerOnActivate` hook of its child.
|
||||
*/
|
||||
activate(nextInstruction: ComponentInstruction): Promise<any> {
|
||||
var previousInstruction = this._currentInstruction;
|
||||
this._currentInstruction = nextInstruction;
|
||||
var componentType = nextInstruction.componentType;
|
||||
var childRouter = this._parentRouter.childRouter(componentType);
|
||||
|
||||
var providers = ReflectiveInjector.resolve([
|
||||
provide(RouteData, {useValue: nextInstruction.routeData}),
|
||||
provide(RouteParams, {useValue: new RouteParams(nextInstruction.params)}),
|
||||
provide(routerMod.Router, {useValue: childRouter})
|
||||
]);
|
||||
this._componentRef =
|
||||
this._loader.loadNextToLocation(componentType, this._viewContainerRef, providers);
|
||||
return this._componentRef.then((componentRef) => {
|
||||
this.activateEvents.emit(componentRef.instance);
|
||||
if (hasLifecycleHook(hookMod.routerOnActivate, componentType)) {
|
||||
return this._componentRef.then(
|
||||
(ref: ComponentRef<any>) =>
|
||||
(<OnActivate>ref.instance).routerOnActivate(nextInstruction, previousInstruction));
|
||||
} else {
|
||||
return componentRef;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the {@link Router} during the commit phase of a navigation when an outlet
|
||||
* reuses a component between different routes.
|
||||
* This method in turn is responsible for calling the `routerOnReuse` hook of its child.
|
||||
*/
|
||||
reuse(nextInstruction: ComponentInstruction): Promise<any> {
|
||||
var previousInstruction = this._currentInstruction;
|
||||
this._currentInstruction = nextInstruction;
|
||||
|
||||
// it's possible the component is removed before it can be reactivated (if nested withing
|
||||
// another dynamically loaded component, for instance). In that case, we simply activate
|
||||
// a new one.
|
||||
if (isBlank(this._componentRef)) {
|
||||
return this.activate(nextInstruction);
|
||||
} else {
|
||||
return PromiseWrapper.resolve(
|
||||
hasLifecycleHook(hookMod.routerOnReuse, this._currentInstruction.componentType) ?
|
||||
this._componentRef.then(
|
||||
(ref: ComponentRef<any>) =>
|
||||
(<OnReuse>ref.instance).routerOnReuse(nextInstruction, previousInstruction)) :
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the {@link Router} when an outlet disposes of a component's contents.
|
||||
* This method in turn is responsible for calling the `routerOnDeactivate` hook of its child.
|
||||
*/
|
||||
deactivate(nextInstruction: ComponentInstruction): Promise<any> {
|
||||
var next = _resolveToTrue;
|
||||
if (isPresent(this._componentRef) && isPresent(this._currentInstruction) &&
|
||||
hasLifecycleHook(hookMod.routerOnDeactivate, this._currentInstruction.componentType)) {
|
||||
next = this._componentRef.then(
|
||||
(ref: ComponentRef<any>) =>
|
||||
(<OnDeactivate>ref.instance)
|
||||
.routerOnDeactivate(nextInstruction, this._currentInstruction));
|
||||
}
|
||||
return next.then((_) => {
|
||||
if (isPresent(this._componentRef)) {
|
||||
var onDispose = this._componentRef.then((ref: ComponentRef<any>) => ref.destroy());
|
||||
this._componentRef = null;
|
||||
return onDispose;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the {@link Router} during recognition phase of a navigation.
|
||||
*
|
||||
* If this resolves to `false`, the given navigation is cancelled.
|
||||
*
|
||||
* This method delegates to the child component's `routerCanDeactivate` hook if it exists,
|
||||
* and otherwise resolves to true.
|
||||
*/
|
||||
routerCanDeactivate(nextInstruction: ComponentInstruction): Promise<boolean> {
|
||||
if (isBlank(this._currentInstruction)) {
|
||||
return _resolveToTrue;
|
||||
}
|
||||
if (hasLifecycleHook(hookMod.routerCanDeactivate, this._currentInstruction.componentType)) {
|
||||
return this._componentRef.then(
|
||||
(ref: ComponentRef<any>) =>
|
||||
(<CanDeactivate>ref.instance)
|
||||
.routerCanDeactivate(nextInstruction, this._currentInstruction));
|
||||
} else {
|
||||
return _resolveToTrue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the {@link Router} during recognition phase of a navigation.
|
||||
*
|
||||
* If the new child component has a different Type than the existing child component,
|
||||
* this will resolve to `false`. You can't reuse an old component when the new component
|
||||
* is of a different Type.
|
||||
*
|
||||
* Otherwise, this method delegates to the child component's `routerCanReuse` hook if it exists,
|
||||
* or resolves to true if the hook is not present.
|
||||
*/
|
||||
routerCanReuse(nextInstruction: ComponentInstruction): Promise<boolean> {
|
||||
var result;
|
||||
|
||||
if (isBlank(this._currentInstruction) ||
|
||||
this._currentInstruction.componentType != nextInstruction.componentType) {
|
||||
result = false;
|
||||
} else if (hasLifecycleHook(hookMod.routerCanReuse, this._currentInstruction.componentType)) {
|
||||
result = this._componentRef.then(
|
||||
(ref: ComponentRef<any>) =>
|
||||
(<CanReuse>ref.instance).routerCanReuse(nextInstruction, this._currentInstruction));
|
||||
} else {
|
||||
result = nextInstruction == this._currentInstruction ||
|
||||
(isPresent(nextInstruction.params) && isPresent(this._currentInstruction.params) &&
|
||||
StringMapWrapper.equals(nextInstruction.params, this._currentInstruction.params));
|
||||
}
|
||||
return <Promise<boolean>>PromiseWrapper.resolve(result);
|
||||
}
|
||||
|
||||
ngOnDestroy(): void { this._parentRouter.unregisterPrimaryOutlet(this); }
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
import {ComponentInstruction} from './instruction';
|
||||
import {global} from '../src/facade/lang';
|
||||
|
||||
// This is here only so that after TS transpilation the file is not empty.
|
||||
// TODO(rado): find a better way to fix this, or remove if likely culprit
|
||||
// https://github.com/systemjs/systemjs/issues/487 gets closed.
|
||||
var __ignore_me = global;
|
||||
var __make_dart_analyzer_happy: Promise<any> = null;
|
||||
|
||||
/**
|
||||
* Defines route lifecycle method `routerOnActivate`, which is called by the router at the end of a
|
||||
* successful route navigation.
|
||||
*
|
||||
* For a single component's navigation, only one of either {@link OnActivate} or {@link OnReuse}
|
||||
* will be called depending on the result of {@link CanReuse}.
|
||||
*
|
||||
* The `routerOnActivate` hook is called with two {@link ComponentInstruction}s as parameters, the
|
||||
* first
|
||||
* representing the current route being navigated to, and the second parameter representing the
|
||||
* previous route or `null`.
|
||||
*
|
||||
* If `routerOnActivate` returns a promise, the route change will wait until the promise settles to
|
||||
* instantiate and activate child components.
|
||||
*
|
||||
* ### Example
|
||||
* {@example router/ts/on_activate/on_activate_example.ts region='routerOnActivate'}
|
||||
*/
|
||||
export interface OnActivate {
|
||||
routerOnActivate(nextInstruction: ComponentInstruction,
|
||||
prevInstruction: ComponentInstruction): any |
|
||||
Promise<any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines route lifecycle method `routerOnReuse`, which is called by the router at the end of a
|
||||
* successful route navigation when {@link CanReuse} is implemented and returns or resolves to true.
|
||||
*
|
||||
* For a single component's navigation, only one of either {@link OnActivate} or {@link OnReuse}
|
||||
* will be called, depending on the result of {@link CanReuse}.
|
||||
*
|
||||
* The `routerOnReuse` hook is called with two {@link ComponentInstruction}s as parameters, the
|
||||
* first
|
||||
* representing the current route being navigated to, and the second parameter representing the
|
||||
* previous route or `null`.
|
||||
*
|
||||
* ### Example
|
||||
* {@example router/ts/reuse/reuse_example.ts region='reuseCmp'}
|
||||
*/
|
||||
export interface OnReuse {
|
||||
routerOnReuse(nextInstruction: ComponentInstruction, prevInstruction: ComponentInstruction): any |
|
||||
Promise<any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines route lifecycle method `routerOnDeactivate`, which is called by the router before
|
||||
* destroying
|
||||
* a component as part of a route change.
|
||||
*
|
||||
* The `routerOnDeactivate` hook is called with two {@link ComponentInstruction}s as parameters, the
|
||||
* first
|
||||
* representing the current route being navigated to, and the second parameter representing the
|
||||
* previous route.
|
||||
*
|
||||
* If `routerOnDeactivate` returns a promise, the route change will wait until the promise settles.
|
||||
*
|
||||
* ### Example
|
||||
* {@example router/ts/on_deactivate/on_deactivate_example.ts region='routerOnDeactivate'}
|
||||
*/
|
||||
export interface OnDeactivate {
|
||||
routerOnDeactivate(nextInstruction: ComponentInstruction,
|
||||
prevInstruction: ComponentInstruction): any |
|
||||
Promise<any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines route lifecycle method `routerCanReuse`, which is called by the router to determine
|
||||
* whether a
|
||||
* component should be reused across routes, or whether to destroy and instantiate a new component.
|
||||
*
|
||||
* The `routerCanReuse` hook is called with two {@link ComponentInstruction}s as parameters, the
|
||||
* first
|
||||
* representing the current route being navigated to, and the second parameter representing the
|
||||
* previous route.
|
||||
*
|
||||
* If `routerCanReuse` returns or resolves to `true`, the component instance will be reused and the
|
||||
* {@link OnDeactivate} hook will be run. If `routerCanReuse` returns or resolves to `false`, a new
|
||||
* component will be instantiated, and the existing component will be deactivated and removed as
|
||||
* part of the navigation.
|
||||
*
|
||||
* If `routerCanReuse` throws or rejects, the navigation will be cancelled.
|
||||
*
|
||||
* ### Example
|
||||
* {@example router/ts/reuse/reuse_example.ts region='reuseCmp'}
|
||||
*/
|
||||
export interface CanReuse {
|
||||
routerCanReuse(nextInstruction: ComponentInstruction,
|
||||
prevInstruction: ComponentInstruction): boolean |
|
||||
Promise<boolean>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines route lifecycle method `routerCanDeactivate`, which is called by the router to determine
|
||||
* if a component can be removed as part of a navigation.
|
||||
*
|
||||
* The `routerCanDeactivate` hook is called with two {@link ComponentInstruction}s as parameters,
|
||||
* the
|
||||
* first representing the current route being navigated to, and the second parameter
|
||||
* representing the previous route.
|
||||
*
|
||||
* If `routerCanDeactivate` returns or resolves to `false`, the navigation is cancelled. If it
|
||||
* returns or
|
||||
* resolves to `true`, then the navigation continues, and the component will be deactivated
|
||||
* (the {@link OnDeactivate} hook will be run) and removed.
|
||||
*
|
||||
* If `routerCanDeactivate` throws or rejects, the navigation is also cancelled.
|
||||
*
|
||||
* ### Example
|
||||
* {@example router/ts/can_deactivate/can_deactivate_example.ts region='routerCanDeactivate'}
|
||||
*/
|
||||
export interface CanDeactivate {
|
||||
routerCanDeactivate(nextInstruction: ComponentInstruction,
|
||||
prevInstruction: ComponentInstruction): boolean |
|
||||
Promise<boolean>;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user