refactor(core): remove getters for packages/animations, language-service, platform-browser, router (#19151)

PR Close #19151
This commit is contained in:
Yuan Gao 2017-09-11 12:39:44 -07:00 committed by Igor Minar
parent 17eaef0311
commit 549f2254b4
13 changed files with 109 additions and 119 deletions

View File

@ -1305,7 +1305,7 @@ export class TransitionAnimationPlayer implements AnimationPlayer {
private _containsRealPlayer = false; private _containsRealPlayer = false;
private _queuedCallbacks: {[name: string]: (() => any)[]} = {}; private _queuedCallbacks: {[name: string]: (() => any)[]} = {};
private _destroyed = false; public readonly destroyed = false;
public parentPlayer: AnimationPlayer; public parentPlayer: AnimationPlayer;
public markedForDestroy: boolean = false; public markedForDestroy: boolean = false;
@ -1314,8 +1314,6 @@ export class TransitionAnimationPlayer implements AnimationPlayer {
get queued() { return this._containsRealPlayer == false; } get queued() { return this._containsRealPlayer == false; }
get destroyed() { return this._destroyed; }
setRealPlayer(player: AnimationPlayer) { setRealPlayer(player: AnimationPlayer) {
if (this._containsRealPlayer) return; if (this._containsRealPlayer) return;
@ -1368,7 +1366,7 @@ export class TransitionAnimationPlayer implements AnimationPlayer {
finish(): void { this._player.finish(); } finish(): void { this._player.finish(); }
destroy(): void { destroy(): void {
this._destroyed = true; (this as{destroyed: boolean}).destroyed = true;
this._player.destroy(); this._player.destroy();
} }

View File

@ -15,7 +15,6 @@ export class WebAnimationsPlayer implements AnimationPlayer {
private _onDoneFns: Function[] = []; private _onDoneFns: Function[] = [];
private _onStartFns: Function[] = []; private _onStartFns: Function[] = [];
private _onDestroyFns: Function[] = []; private _onDestroyFns: Function[] = [];
private _player: DOMAnimation;
private _duration: number; private _duration: number;
private _delay: number; private _delay: number;
private _initialized = false; private _initialized = false;
@ -23,6 +22,8 @@ export class WebAnimationsPlayer implements AnimationPlayer {
private _started = false; private _started = false;
private _destroyed = false; private _destroyed = false;
private _finalKeyframe: {[key: string]: string | number}; private _finalKeyframe: {[key: string]: string | number};
public readonly domPlayer: DOMAnimation;
public time = 0; public time = 0;
public parentPlayer: AnimationPlayer|null = null; public parentPlayer: AnimationPlayer|null = null;
@ -86,9 +87,10 @@ export class WebAnimationsPlayer implements AnimationPlayer {
} }
} }
this._player = this._triggerWebAnimation(this.element, keyframes, this.options); (this as{domPlayer: DOMAnimation}).domPlayer =
this._triggerWebAnimation(this.element, keyframes, this.options);
this._finalKeyframe = keyframes.length ? keyframes[keyframes.length - 1] : {}; this._finalKeyframe = keyframes.length ? keyframes[keyframes.length - 1] : {};
this._player.addEventListener('finish', () => this._onFinish()); this.domPlayer.addEventListener('finish', () => this._onFinish());
} }
private _preparePlayerBeforeStart() { private _preparePlayerBeforeStart() {
@ -96,7 +98,7 @@ export class WebAnimationsPlayer implements AnimationPlayer {
if (this._delay) { if (this._delay) {
this._resetDomPlayerState(); this._resetDomPlayerState();
} else { } else {
this._player.pause(); this.domPlayer.pause();
} }
} }
@ -107,8 +109,6 @@ export class WebAnimationsPlayer implements AnimationPlayer {
return element['animate'](keyframes, options) as DOMAnimation; return element['animate'](keyframes, options) as DOMAnimation;
} }
get domPlayer() { return this._player; }
onStart(fn: () => void): void { this._onStartFns.push(fn); } onStart(fn: () => void): void { this._onStartFns.push(fn); }
onDone(fn: () => void): void { this._onDoneFns.push(fn); } onDone(fn: () => void): void { this._onDoneFns.push(fn); }
@ -122,18 +122,18 @@ export class WebAnimationsPlayer implements AnimationPlayer {
this._onStartFns = []; this._onStartFns = [];
this._started = true; this._started = true;
} }
this._player.play(); this.domPlayer.play();
} }
pause(): void { pause(): void {
this.init(); this.init();
this._player.pause(); this.domPlayer.pause();
} }
finish(): void { finish(): void {
this.init(); this.init();
this._onFinish(); this._onFinish();
this._player.finish(); this.domPlayer.finish();
} }
reset(): void { reset(): void {
@ -144,8 +144,8 @@ export class WebAnimationsPlayer implements AnimationPlayer {
} }
private _resetDomPlayerState() { private _resetDomPlayerState() {
if (this._player) { if (this.domPlayer) {
this._player.cancel(); this.domPlayer.cancel();
} }
} }
@ -166,9 +166,9 @@ export class WebAnimationsPlayer implements AnimationPlayer {
} }
} }
setPosition(p: number): void { this._player.currentTime = p * this.time; } setPosition(p: number): void { this.domPlayer.currentTime = p * this.time; }
getPosition(): number { return this._player.currentTime / this.time; } getPosition(): number { return this.domPlayer.currentTime / this.time; }
get totalTime(): number { return this._delay + this._duration; } get totalTime(): number { return this._delay + this._duration; }

View File

@ -19,17 +19,19 @@ export class AnimationGroupPlayer implements AnimationPlayer {
public parentPlayer: AnimationPlayer|null = null; public parentPlayer: AnimationPlayer|null = null;
public totalTime: number = 0; public totalTime: number = 0;
public readonly players: AnimationPlayer[];
constructor(private _players: AnimationPlayer[]) { constructor(_players: AnimationPlayer[]) {
this.players = _players;
let doneCount = 0; let doneCount = 0;
let destroyCount = 0; let destroyCount = 0;
let startCount = 0; let startCount = 0;
const total = this._players.length; const total = this.players.length;
if (total == 0) { if (total == 0) {
scheduleMicroTask(() => this._onFinish()); scheduleMicroTask(() => this._onFinish());
} else { } else {
this._players.forEach(player => { this.players.forEach(player => {
player.parentPlayer = this; player.parentPlayer = this;
player.onDone(() => { player.onDone(() => {
if (++doneCount >= total) { if (++doneCount >= total) {
@ -49,7 +51,7 @@ export class AnimationGroupPlayer implements AnimationPlayer {
}); });
} }
this.totalTime = this._players.reduce((time, player) => Math.max(time, player.totalTime), 0); this.totalTime = this.players.reduce((time, player) => Math.max(time, player.totalTime), 0);
} }
private _onFinish() { private _onFinish() {
@ -60,7 +62,7 @@ export class AnimationGroupPlayer implements AnimationPlayer {
} }
} }
init(): void { this._players.forEach(player => player.init()); } init(): void { this.players.forEach(player => player.init()); }
onStart(fn: () => void): void { this._onStartFns.push(fn); } onStart(fn: () => void): void { this._onStartFns.push(fn); }
@ -83,16 +85,16 @@ export class AnimationGroupPlayer implements AnimationPlayer {
this.init(); this.init();
} }
this._onStart(); this._onStart();
this._players.forEach(player => player.play()); this.players.forEach(player => player.play());
} }
pause(): void { this._players.forEach(player => player.pause()); } pause(): void { this.players.forEach(player => player.pause()); }
restart(): void { this._players.forEach(player => player.restart()); } restart(): void { this.players.forEach(player => player.restart()); }
finish(): void { finish(): void {
this._onFinish(); this._onFinish();
this._players.forEach(player => player.finish()); this.players.forEach(player => player.finish());
} }
destroy(): void { this._onDestroy(); } destroy(): void { this._onDestroy(); }
@ -101,14 +103,14 @@ export class AnimationGroupPlayer implements AnimationPlayer {
if (!this._destroyed) { if (!this._destroyed) {
this._destroyed = true; this._destroyed = true;
this._onFinish(); this._onFinish();
this._players.forEach(player => player.destroy()); this.players.forEach(player => player.destroy());
this._onDestroyFns.forEach(fn => fn()); this._onDestroyFns.forEach(fn => fn());
this._onDestroyFns = []; this._onDestroyFns = [];
} }
} }
reset(): void { reset(): void {
this._players.forEach(player => player.reset()); this.players.forEach(player => player.reset());
this._destroyed = false; this._destroyed = false;
this._finished = false; this._finished = false;
this._started = false; this._started = false;
@ -116,7 +118,7 @@ export class AnimationGroupPlayer implements AnimationPlayer {
setPosition(p: number): void { setPosition(p: number): void {
const timeAtPosition = p * this.totalTime; const timeAtPosition = p * this.totalTime;
this._players.forEach(player => { this.players.forEach(player => {
const position = player.totalTime ? Math.min(1, timeAtPosition / player.totalTime) : 1; const position = player.totalTime ? Math.min(1, timeAtPosition / player.totalTime) : 1;
player.setPosition(position); player.setPosition(position);
}); });
@ -124,15 +126,13 @@ export class AnimationGroupPlayer implements AnimationPlayer {
getPosition(): number { getPosition(): number {
let min = 0; let min = 0;
this._players.forEach(player => { this.players.forEach(player => {
const p = player.getPosition(); const p = player.getPosition();
min = Math.min(p, min); min = Math.min(p, min);
}); });
return min; return min;
} }
get players(): AnimationPlayer[] { return this._players; }
beforeDestroy(): void { beforeDestroy(): void {
this.players.forEach(player => { this.players.forEach(player => {
if (player.beforeDestroy) { if (player.beforeDestroy) {

View File

@ -18,13 +18,16 @@
* @stable * @stable
*/ */
export class Version { export class Version {
constructor(public full: string) {} public readonly major: string;
public readonly minor: string;
public readonly patch: string;
get major(): string { return this.full.split('.')[0]; } constructor(public full: string) {
const splits = full.split('.');
get minor(): string { return this.full.split('.')[1]; } this.major = splits[0];
this.minor = splits[1];
get patch(): string { return this.full.split('.').slice(2).join('.'); } this.patch = splits.slice(2).join('.');
}
} }
/** /**

View File

@ -169,12 +169,11 @@ function invertMap(obj: {[name: string]: string}): {[name: string]: string} {
* Wrap a symbol and change its kind to component. * Wrap a symbol and change its kind to component.
*/ */
class OverrideKindSymbol implements Symbol { class OverrideKindSymbol implements Symbol {
constructor(private sym: Symbol, private kindOverride: string) {} public readonly kind: string;
constructor(private sym: Symbol, kindOverride: string) { this.kind = kindOverride; }
get name(): string { return this.sym.name; } get name(): string { return this.sym.name; }
get kind(): string { return this.kindOverride; }
get language(): string { return this.sym.language; } get language(): string { return this.sym.language; }
get type(): Symbol|undefined { return this.sym.type; } get type(): Symbol|undefined { return this.sym.type; }

View File

@ -32,8 +32,9 @@ const baseHtmlParser = new InjectionToken('HtmlParser');
export class CompilerImpl implements Compiler { export class CompilerImpl implements Compiler {
private _delegate: JitCompiler; private _delegate: JitCompiler;
public readonly injector: Injector;
constructor( constructor(
private _injector: Injector, private _metadataResolver: CompileMetadataResolver, injector: Injector, private _metadataResolver: CompileMetadataResolver,
templateParser: TemplateParser, styleCompiler: StyleCompiler, viewCompiler: ViewCompiler, templateParser: TemplateParser, styleCompiler: StyleCompiler, viewCompiler: ViewCompiler,
ngModuleCompiler: NgModuleCompiler, summaryResolver: SummaryResolver<Type<any>>, ngModuleCompiler: NgModuleCompiler, summaryResolver: SummaryResolver<Type<any>>,
compileReflector: CompileReflector, compilerConfig: CompilerConfig, console: Console) { compileReflector: CompileReflector, compilerConfig: CompilerConfig, console: Console) {
@ -41,10 +42,9 @@ export class CompilerImpl implements Compiler {
_metadataResolver, templateParser, styleCompiler, viewCompiler, ngModuleCompiler, _metadataResolver, templateParser, styleCompiler, viewCompiler, ngModuleCompiler,
summaryResolver, compileReflector, compilerConfig, console, summaryResolver, compileReflector, compilerConfig, console,
this.getExtraNgModuleProviders.bind(this)); this.getExtraNgModuleProviders.bind(this));
this.injector = injector;
} }
get injector(): Injector { return this._injector; }
private getExtraNgModuleProviders() { private getExtraNgModuleProviders() {
return [this._metadataResolver.getProviderMetadata( return [this._metadataResolver.getProviderMetadata(
new ProviderMeta(Compiler, {useValue: this}))]; new ProviderMeta(Compiler, {useValue: this}))];

View File

@ -23,7 +23,7 @@ import {supportsState} from './history';
*/ */
@Injectable() @Injectable()
export class BrowserPlatformLocation extends PlatformLocation { export class BrowserPlatformLocation extends PlatformLocation {
private _location: Location; public readonly location: Location;
private _history: History; private _history: History;
constructor(@Inject(DOCUMENT) private _doc: any) { constructor(@Inject(DOCUMENT) private _doc: any) {
@ -34,12 +34,10 @@ export class BrowserPlatformLocation extends PlatformLocation {
// This is moved to its own method so that `MockPlatformLocationStrategy` can overwrite it // This is moved to its own method so that `MockPlatformLocationStrategy` can overwrite it
/** @internal */ /** @internal */
_init() { _init() {
this._location = getDOM().getLocation(); (this as{location: Location}).location = getDOM().getLocation();
this._history = getDOM().getHistory(); this._history = getDOM().getHistory();
} }
get location(): Location { return this._location; }
getBaseHrefFromDOM(): string { return getDOM().getBaseHref(this._doc) !; } getBaseHrefFromDOM(): string { return getDOM().getBaseHref(this._doc) !; }
onPopState(fn: LocationChangeListener): void { onPopState(fn: LocationChangeListener): void {
@ -50,16 +48,16 @@ export class BrowserPlatformLocation extends PlatformLocation {
getDOM().getGlobalEventTarget(this._doc, 'window').addEventListener('hashchange', fn, false); getDOM().getGlobalEventTarget(this._doc, 'window').addEventListener('hashchange', fn, false);
} }
get pathname(): string { return this._location.pathname; } get pathname(): string { return this.location.pathname; }
get search(): string { return this._location.search; } get search(): string { return this.location.search; }
get hash(): string { return this._location.hash; } get hash(): string { return this.location.hash; }
set pathname(newPath: string) { this._location.pathname = newPath; } set pathname(newPath: string) { this.location.pathname = newPath; }
pushState(state: any, title: string, url: string): void { pushState(state: any, title: string, url: string): void {
if (supportsState()) { if (supportsState()) {
this._history.pushState(state, title, url); this._history.pushState(state, title, url);
} else { } else {
this._location.hash = url; this.location.hash = url;
} }
} }
@ -67,7 +65,7 @@ export class BrowserPlatformLocation extends PlatformLocation {
if (supportsState()) { if (supportsState()) {
this._history.replaceState(state, title, url); this._history.replaceState(state, title, url);
} else { } else {
this._location.hash = url; this.location.hash = url;
} }
} }

View File

@ -29,9 +29,9 @@ function parseUrl(urlStr: string): {pathname: string, search: string, hash: stri
*/ */
@Injectable() @Injectable()
export class ServerPlatformLocation implements PlatformLocation { export class ServerPlatformLocation implements PlatformLocation {
private _path: string = '/'; public readonly pathname: string = '/';
private _search: string = ''; public readonly search: string = '';
private _hash: string = ''; public readonly hash: string = '';
private _hashUpdate = new Subject<LocationChangeEvent>(); private _hashUpdate = new Subject<LocationChangeEvent>();
constructor( constructor(
@ -39,9 +39,9 @@ export class ServerPlatformLocation implements PlatformLocation {
const config = _config as PlatformConfig | null; const config = _config as PlatformConfig | null;
if (!!config && !!config.url) { if (!!config && !!config.url) {
const parsedUrl = parseUrl(config.url); const parsedUrl = parseUrl(config.url);
this._path = parsedUrl.pathname; this.pathname = parsedUrl.pathname;
this._search = parsedUrl.search; this.search = parsedUrl.search;
this._hash = parsedUrl.hash; this.hash = parsedUrl.hash;
} }
} }
@ -54,18 +54,14 @@ export class ServerPlatformLocation implements PlatformLocation {
onHashChange(fn: LocationChangeListener): void { this._hashUpdate.subscribe(fn); } onHashChange(fn: LocationChangeListener): void { this._hashUpdate.subscribe(fn); }
get pathname(): string { return this._path; }
get search(): string { return this._search; }
get hash(): string { return this._hash; }
get url(): string { return `${this.pathname}${this.search}${this.hash}`; } get url(): string { return `${this.pathname}${this.search}${this.hash}`; }
private setHash(value: string, oldUrl: string) { private setHash(value: string, oldUrl: string) {
if (this._hash === value) { if (this.hash === value) {
// Don't fire events if the hash has not changed. // Don't fire events if the hash has not changed.
return; return;
} }
this._hash = value; (this as{hash: string}).hash = value;
const newUrl = this.url; const newUrl = this.url;
scheduleMicroTask( scheduleMicroTask(
() => this._hashUpdate.next({ type: 'hashchange', oldUrl, newUrl } as LocationChangeEvent)); () => this._hashUpdate.next({ type: 'hashchange', oldUrl, newUrl } as LocationChangeEvent));
@ -74,8 +70,8 @@ export class ServerPlatformLocation implements PlatformLocation {
replaceState(state: any, title: string, newUrl: string): void { replaceState(state: any, title: string, newUrl: string): void {
const oldUrl = this.url; const oldUrl = this.url;
const parsedUrl = parseUrl(newUrl); const parsedUrl = parseUrl(newUrl);
this._path = parsedUrl.pathname; (this as{pathname: string}).pathname = parsedUrl.pathname;
this._search = parsedUrl.search; (this as{search: string}).search = parsedUrl.search;
this.setHash(parsedUrl.hash, oldUrl); this.setHash(parsedUrl.hash, oldUrl);
} }

View File

@ -86,7 +86,7 @@ export class RouterLinkActive implements OnChanges,
private classes: string[] = []; private classes: string[] = [];
private subscription: Subscription; private subscription: Subscription;
private active: boolean = false; public readonly isActive: boolean = false;
@Input() routerLinkActiveOptions: {exact: boolean} = {exact: false}; @Input() routerLinkActiveOptions: {exact: boolean} = {exact: false};
@ -100,7 +100,6 @@ export class RouterLinkActive implements OnChanges,
}); });
} }
get isActive(): boolean { return this.active; }
ngAfterContentInit(): void { ngAfterContentInit(): void {
this.links.changes.subscribe(_ => this.update()); this.links.changes.subscribe(_ => this.update());
@ -122,7 +121,7 @@ export class RouterLinkActive implements OnChanges,
const hasActiveLinks = this.hasActiveLinks(); const hasActiveLinks = this.hasActiveLinks();
// react only when status has changed to prevent unnecessary dom updates // react only when status has changed to prevent unnecessary dom updates
if (this.active !== hasActiveLinks) { if (this.isActive !== hasActiveLinks) {
this.classes.forEach((c) => { this.classes.forEach((c) => {
if (hasActiveLinks) { if (hasActiveLinks) {
this.renderer.addClass(this.element.nativeElement, c); this.renderer.addClass(this.element.nativeElement, c);
@ -130,7 +129,9 @@ export class RouterLinkActive implements OnChanges,
this.renderer.removeClass(this.element.nativeElement, c); this.renderer.removeClass(this.element.nativeElement, c);
} }
}); });
Promise.resolve(hasActiveLinks).then(active => this.active = active); Promise.resolve(hasActiveLinks).then(active => (this as{
isActive: boolean
}).isActive = active);
} }
} }

View File

@ -128,7 +128,7 @@ export class RouterOutlet implements OnDestroy, OnInit {
} }
this._activatedRoute = activatedRoute; this._activatedRoute = activatedRoute;
const snapshot = activatedRoute._futureSnapshot; const snapshot = activatedRoute._futureSnapshot;
const component = <any>snapshot._routeConfig !.component; const component = <any>snapshot.routeConfig !.component;
resolver = resolver || this.resolver; resolver = resolver || this.resolver;
const factory = resolver.resolveComponentFactory(component); const factory = resolver.resolveComponentFactory(component);
const childContexts = this.parentContexts.getOrCreateContext(this.name).children; const childContexts = this.parentContexts.getOrCreateContext(this.name).children;

View File

@ -108,9 +108,9 @@ export class PreActivation {
const context = parentContexts ? parentContexts.getContext(futureNode.value.outlet) : null; const context = parentContexts ? parentContexts.getContext(futureNode.value.outlet) : null;
// reusing the node // reusing the node
if (curr && future._routeConfig === curr._routeConfig) { if (curr && future.routeConfig === curr.routeConfig) {
const shouldRunGuardsAndResolvers = this.shouldRunGuardsAndResolvers( const shouldRunGuardsAndResolvers = this.shouldRunGuardsAndResolvers(
curr, future, future._routeConfig !.runGuardsAndResolvers); curr, future, future.routeConfig !.runGuardsAndResolvers);
if (shouldRunGuardsAndResolvers) { if (shouldRunGuardsAndResolvers) {
this.canActivateChecks.push(new CanActivate(futurePath)); this.canActivateChecks.push(new CanActivate(futurePath));
} else { } else {
@ -241,7 +241,7 @@ export class PreActivation {
} }
private runCanActivate(future: ActivatedRouteSnapshot): Observable<boolean> { private runCanActivate(future: ActivatedRouteSnapshot): Observable<boolean> {
const canActivate = future._routeConfig ? future._routeConfig.canActivate : null; const canActivate = future.routeConfig ? future.routeConfig.canActivate : null;
if (!canActivate || canActivate.length === 0) return of (true); if (!canActivate || canActivate.length === 0) return of (true);
const obs = map.call(from(canActivate), (c: any) => { const obs = map.call(from(canActivate), (c: any) => {
const guard = this.getToken(c, future); const guard = this.getToken(c, future);
@ -281,14 +281,14 @@ export class PreActivation {
private extractCanActivateChild(p: ActivatedRouteSnapshot): private extractCanActivateChild(p: ActivatedRouteSnapshot):
{node: ActivatedRouteSnapshot, guards: any[]}|null { {node: ActivatedRouteSnapshot, guards: any[]}|null {
const canActivateChild = p._routeConfig ? p._routeConfig.canActivateChild : null; const canActivateChild = p.routeConfig ? p.routeConfig.canActivateChild : null;
if (!canActivateChild || canActivateChild.length === 0) return null; if (!canActivateChild || canActivateChild.length === 0) return null;
return {node: p, guards: canActivateChild}; return {node: p, guards: canActivateChild};
} }
private runCanDeactivate(component: Object|null, curr: ActivatedRouteSnapshot): private runCanDeactivate(component: Object|null, curr: ActivatedRouteSnapshot):
Observable<boolean> { Observable<boolean> {
const canDeactivate = curr && curr._routeConfig ? curr._routeConfig.canDeactivate : null; const canDeactivate = curr && curr.routeConfig ? curr.routeConfig.canDeactivate : null;
if (!canDeactivate || canDeactivate.length === 0) return of (true); if (!canDeactivate || canDeactivate.length === 0) return of (true);
const canDeactivate$ = mergeMap.call(from(canDeactivate), (c: any) => { const canDeactivate$ = mergeMap.call(from(canDeactivate), (c: any) => {
const guard = this.getToken(c, curr); const guard = this.getToken(c, curr);
@ -351,7 +351,7 @@ function closestLoadedConfig(snapshot: ActivatedRouteSnapshot): LoadedRouterConf
if (!snapshot) return null; if (!snapshot) return null;
for (let s = snapshot.parent; s; s = s.parent) { for (let s = snapshot.parent; s; s = s.parent) {
const route = s._routeConfig; const route = s.routeConfig;
if (route && route._loadedConfig) return route._loadedConfig; if (route && route._loadedConfig) return route._loadedConfig;
} }

View File

@ -200,16 +200,16 @@ function defaultRouterHook(snapshot: RouterStateSnapshot): Observable<void> {
export class Router { export class Router {
private currentUrlTree: UrlTree; private currentUrlTree: UrlTree;
private rawUrlTree: UrlTree; private rawUrlTree: UrlTree;
private navigations = new BehaviorSubject<NavigationParams>(null !); private navigations = new BehaviorSubject<NavigationParams>(null !);
private routerEvents = new Subject<Event>();
private currentRouterState: RouterState;
private locationSubscription: Subscription; private locationSubscription: Subscription;
private navigationId: number = 0; private navigationId: number = 0;
private configLoader: RouterConfigLoader; private configLoader: RouterConfigLoader;
private ngModule: NgModuleRef<any>; private ngModule: NgModuleRef<any>;
public readonly events: Observable<Event> = new Subject<Event>();
public readonly routerState: RouterState;
/** /**
* Error handler that is invoked when a navigation errors. * Error handler that is invoked when a navigation errors.
* *
@ -259,7 +259,7 @@ export class Router {
this.rawUrlTree = this.currentUrlTree; this.rawUrlTree = this.currentUrlTree;
this.configLoader = new RouterConfigLoader(loader, compiler, onLoadStart, onLoadEnd); this.configLoader = new RouterConfigLoader(loader, compiler, onLoadStart, onLoadEnd);
this.currentRouterState = createEmptyState(this.currentUrlTree, this.rootComponentType); this.routerState = createEmptyState(this.currentUrlTree, this.rootComponentType);
this.processNavigations(); this.processNavigations();
} }
@ -271,7 +271,7 @@ export class Router {
this.rootComponentType = rootComponentType; this.rootComponentType = rootComponentType;
// TODO: vsavkin router 4.0 should make the root component set to null // TODO: vsavkin router 4.0 should make the root component set to null
// this will simplify the lifecycle of the router. // this will simplify the lifecycle of the router.
this.currentRouterState.root.component = this.rootComponentType; this.routerState.root.component = this.rootComponentType;
} }
/** /**
@ -299,17 +299,11 @@ export class Router {
} }
} }
/** The current route state */
get routerState(): RouterState { return this.currentRouterState; }
/** The current url */ /** The current url */
get url(): string { return this.serializeUrl(this.currentUrlTree); } get url(): string { return this.serializeUrl(this.currentUrlTree); }
/** An observable of router events */
get events(): Observable<Event> { return this.routerEvents; }
/** @internal */ /** @internal */
triggerEvent(e: Event): void { this.routerEvents.next(e); } triggerEvent(e: Event): void { (this.events as Subject<Event>).next(e); }
/** /**
* Resets the configuration used for navigation and generating links. * Resets the configuration used for navigation and generating links.
@ -552,7 +546,7 @@ export class Router {
const urlTransition = !this.navigated || url.toString() !== this.currentUrlTree.toString(); const urlTransition = !this.navigated || url.toString() !== this.currentUrlTree.toString();
if (urlTransition && this.urlHandlingStrategy.shouldProcessUrl(rawUrl)) { if (urlTransition && this.urlHandlingStrategy.shouldProcessUrl(rawUrl)) {
this.routerEvents.next(new NavigationStart(id, this.serializeUrl(url))); (this.events as Subject<Event>).next(new NavigationStart(id, this.serializeUrl(url)));
Promise.resolve() Promise.resolve()
.then( .then(
(_) => this.runNavigate( (_) => this.runNavigate(
@ -564,7 +558,7 @@ export class Router {
} else if ( } else if (
urlTransition && this.rawUrlTree && urlTransition && this.rawUrlTree &&
this.urlHandlingStrategy.shouldProcessUrl(this.rawUrlTree)) { this.urlHandlingStrategy.shouldProcessUrl(this.rawUrlTree)) {
this.routerEvents.next(new NavigationStart(id, this.serializeUrl(url))); (this.events as Subject<Event>).next(new NavigationStart(id, this.serializeUrl(url)));
Promise.resolve() Promise.resolve()
.then( .then(
(_) => this.runNavigate( (_) => this.runNavigate(
@ -583,9 +577,10 @@ export class Router {
id: number, precreatedState: RouterStateSnapshot|null): Promise<boolean> { id: number, precreatedState: RouterStateSnapshot|null): Promise<boolean> {
if (id !== this.navigationId) { if (id !== this.navigationId) {
this.location.go(this.urlSerializer.serialize(this.currentUrlTree)); this.location.go(this.urlSerializer.serialize(this.currentUrlTree));
this.routerEvents.next(new NavigationCancel( (this.events as Subject<Event>)
id, this.serializeUrl(url), .next(new NavigationCancel(
`Navigation ID ${id} is not equal to the current navigation id ${this.navigationId}`)); id, this.serializeUrl(url),
`Navigation ID ${id} is not equal to the current navigation id ${this.navigationId}`));
return Promise.resolve(false); return Promise.resolve(false);
} }
@ -604,8 +599,9 @@ export class Router {
this.rootComponentType, this.config, appliedUrl, this.serializeUrl(appliedUrl)), this.rootComponentType, this.config, appliedUrl, this.serializeUrl(appliedUrl)),
(snapshot: any) => { (snapshot: any) => {
this.routerEvents.next(new RoutesRecognized( (this.events as Subject<Event>)
id, this.serializeUrl(url), this.serializeUrl(appliedUrl), snapshot)); .next(new RoutesRecognized(
id, this.serializeUrl(url), this.serializeUrl(appliedUrl), snapshot));
return {appliedUrl, snapshot}; return {appliedUrl, snapshot};
}); });
@ -627,7 +623,7 @@ export class Router {
({appliedUrl, snapshot}: {appliedUrl: string, snapshot: RouterStateSnapshot}) => { ({appliedUrl, snapshot}: {appliedUrl: string, snapshot: RouterStateSnapshot}) => {
const moduleInjector = this.ngModule.injector; const moduleInjector = this.ngModule.injector;
preActivation = new PreActivation( preActivation = new PreActivation(
snapshot, this.currentRouterState.snapshot, moduleInjector, snapshot, this.routerState.snapshot, moduleInjector,
(evt: Event) => this.triggerEvent(evt)); (evt: Event) => this.triggerEvent(evt));
preActivation.initalize(this.rootContexts); preActivation.initalize(this.rootContexts);
return {appliedUrl, snapshot}; return {appliedUrl, snapshot};
@ -676,8 +672,7 @@ export class Router {
const routerState$ = const routerState$ =
map.call(preactivationDone$, ({appliedUrl, snapshot, shouldActivate}: any) => { map.call(preactivationDone$, ({appliedUrl, snapshot, shouldActivate}: any) => {
if (shouldActivate) { if (shouldActivate) {
const state = const state = createRouterState(this.routeReuseStrategy, snapshot, this.routerState);
createRouterState(this.routeReuseStrategy, snapshot, this.currentRouterState);
return {appliedUrl, state, shouldActivate}; return {appliedUrl, state, shouldActivate};
} else { } else {
return {appliedUrl, state: null, shouldActivate}; return {appliedUrl, state: null, shouldActivate};
@ -688,7 +683,7 @@ export class Router {
// applied the new router state // applied the new router state
// this operation has side effects // this operation has side effects
let navigationIsSuccessful: boolean; let navigationIsSuccessful: boolean;
const storedState = this.currentRouterState; const storedState = this.routerState;
const storedUrl = this.currentUrlTree; const storedUrl = this.currentUrlTree;
routerState$ routerState$
@ -701,7 +696,7 @@ export class Router {
this.currentUrlTree = appliedUrl; this.currentUrlTree = appliedUrl;
this.rawUrlTree = this.urlHandlingStrategy.merge(this.currentUrlTree, rawUrl); this.rawUrlTree = this.urlHandlingStrategy.merge(this.currentUrlTree, rawUrl);
this.currentRouterState = state; (this as{routerState: RouterState}).routerState = state;
if (!shouldPreventPushState) { if (!shouldPreventPushState) {
const path = this.urlSerializer.serialize(this.rawUrlTree); const path = this.urlSerializer.serialize(this.rawUrlTree);
@ -722,12 +717,14 @@ export class Router {
() => { () => {
if (navigationIsSuccessful) { if (navigationIsSuccessful) {
this.navigated = true; this.navigated = true;
this.routerEvents.next(new NavigationEnd( (this.events as Subject<Event>)
id, this.serializeUrl(url), this.serializeUrl(this.currentUrlTree))); .next(new NavigationEnd(
id, this.serializeUrl(url), this.serializeUrl(this.currentUrlTree)));
resolvePromise(true); resolvePromise(true);
} else { } else {
this.resetUrlToCurrentUrlTree(); this.resetUrlToCurrentUrlTree();
this.routerEvents.next(new NavigationCancel(id, this.serializeUrl(url), '')); (this.events as Subject<Event>)
.next(new NavigationCancel(id, this.serializeUrl(url), ''));
resolvePromise(false); resolvePromise(false);
} }
}, },
@ -735,11 +732,12 @@ export class Router {
if (isNavigationCancelingError(e)) { if (isNavigationCancelingError(e)) {
this.resetUrlToCurrentUrlTree(); this.resetUrlToCurrentUrlTree();
this.navigated = true; this.navigated = true;
this.routerEvents.next( (this.events as Subject<Event>)
new NavigationCancel(id, this.serializeUrl(url), e.message)); .next(new NavigationCancel(id, this.serializeUrl(url), e.message));
resolvePromise(false); resolvePromise(false);
} else { } else {
this.routerEvents.next(new NavigationError(id, this.serializeUrl(url), e)); (this.events as Subject<Event>)
.next(new NavigationError(id, this.serializeUrl(url), e));
try { try {
resolvePromise(this.errorHandler(e)); resolvePromise(this.errorHandler(e));
} catch (ee) { } catch (ee) {
@ -747,7 +745,7 @@ export class Router {
} }
} }
this.currentRouterState = storedState; (this as{routerState: RouterState}).routerState = storedState;
this.currentUrlTree = storedUrl; this.currentUrlTree = storedUrl;
this.rawUrlTree = this.urlHandlingStrategy.merge(this.currentUrlTree, rawUrl); this.rawUrlTree = this.urlHandlingStrategy.merge(this.currentUrlTree, rawUrl);
this.location.replaceState(this.serializeUrl(this.rawUrlTree)); this.location.replaceState(this.serializeUrl(this.rawUrlTree));
@ -936,7 +934,7 @@ function advanceActivatedRouteNodeAndItsChildren(node: TreeNode<ActivatedRoute>)
function parentLoadedConfig(snapshot: ActivatedRouteSnapshot): LoadedRouterConfig|null { function parentLoadedConfig(snapshot: ActivatedRouteSnapshot): LoadedRouterConfig|null {
for (let s = snapshot.parent; s; s = s.parent) { for (let s = snapshot.parent; s; s = s.parent) {
const route = s._routeConfig; const route = s.routeConfig;
if (route && route._loadedConfig) return route._loadedConfig; if (route && route._loadedConfig) return route._loadedConfig;
if (route && route.component) return null; if (route && route.component) return null;
} }

View File

@ -233,8 +233,8 @@ export function inheritedParamsDataResolve(route: ActivatedRouteSnapshot): Inher
* @stable * @stable
*/ */
export class ActivatedRouteSnapshot { export class ActivatedRouteSnapshot {
/** @internal **/ /** The configuration used to match this route **/
_routeConfig: Route|null; public readonly routeConfig: Route|null;
/** @internal **/ /** @internal **/
_urlSegment: UrlSegmentGroup; _urlSegment: UrlSegmentGroup;
/** @internal */ /** @internal */
@ -267,15 +267,12 @@ export class ActivatedRouteSnapshot {
/** The component of the route */ /** The component of the route */
public component: Type<any>|string|null, routeConfig: Route|null, urlSegment: UrlSegmentGroup, public component: Type<any>|string|null, routeConfig: Route|null, urlSegment: UrlSegmentGroup,
lastPathIndex: number, resolve: ResolveData) { lastPathIndex: number, resolve: ResolveData) {
this._routeConfig = routeConfig; this.routeConfig = routeConfig;
this._urlSegment = urlSegment; this._urlSegment = urlSegment;
this._lastPathIndex = lastPathIndex; this._lastPathIndex = lastPathIndex;
this._resolve = resolve; this._resolve = resolve;
} }
/** The configuration used to match this route */
get routeConfig(): Route|null { return this._routeConfig; }
/** The root of the router state */ /** The root of the router state */
get root(): ActivatedRouteSnapshot { return this._routerState.root; } get root(): ActivatedRouteSnapshot { return this._routerState.root; }
@ -307,7 +304,7 @@ export class ActivatedRouteSnapshot {
toString(): string { toString(): string {
const url = this.url.map(segment => segment.toString()).join('/'); const url = this.url.map(segment => segment.toString()).join('/');
const matched = this._routeConfig ? this._routeConfig.path : ''; const matched = this.routeConfig ? this.routeConfig.path : '';
return `Route(url:'${url}', path:'${matched}')`; return `Route(url:'${url}', path:'${matched}')`;
} }
} }
@ -400,4 +397,4 @@ export function equalParamsAndUrlSegments(
return equalUrlParams && !parentsMismatch && return equalUrlParams && !parentsMismatch &&
(!a.parent || equalParamsAndUrlSegments(a.parent, b.parent !)); (!a.parent || equalParamsAndUrlSegments(a.parent, b.parent !));
} }