fix(router): openning links in new tab

Clicks on router-link should not prevent browser default action when
any mouse button other than left mouse button or ctrl/meta key is pressed.

router-link href should use location strategy external url.

Closes #5908
Closes #6806
Closes #7749
Closes #8806

Closes #8821
This commit is contained in:
Dimitrios Loukadakis 2016-05-25 01:23:46 +03:00 committed by Misko Hevery
parent 172a5663ef
commit fa2ce8100b
2 changed files with 23 additions and 16 deletions

View File

@ -3,6 +3,7 @@ import {Router} from '../router';
import {RouteSegment} from '../segments'; import {RouteSegment} from '../segments';
import {isString, isArray, isPresent} from '../facade/lang'; import {isString, isArray, isPresent} from '../facade/lang';
import {ObservableWrapper} from '../facade/async'; import {ObservableWrapper} from '../facade/async';
import {LocationStrategy} from '@angular/common';
/** /**
* The RouterLink directive lets you link to specific parts of your app. * The RouterLink directive lets you link to specific parts of your app.
@ -44,7 +45,8 @@ export class RouterLink implements OnDestroy {
@HostBinding() href: string; @HostBinding() href: string;
@HostBinding('class.router-link-active') isActive: boolean = false; @HostBinding('class.router-link-active') isActive: boolean = false;
constructor(private _routeSegment: RouteSegment, private _router: Router) { constructor(private _routeSegment: RouteSegment, private _router: Router,
private _locationStrategy: LocationStrategy) {
// because auxiliary links take existing primary and auxiliary routes into account, // because auxiliary links take existing primary and auxiliary routes into account,
// we need to update the link whenever params or other routes change. // we need to update the link whenever params or other routes change.
this._subscription = this._subscription =
@ -64,20 +66,24 @@ export class RouterLink implements OnDestroy {
} }
@HostListener("click") @HostListener("click", ["$event.button", "$event.ctrlKey", "$event.metaKey"])
onClick(): boolean { onClick(button: number, ctrlKey: boolean, metaKey: boolean): boolean {
// If no target, or if target is _self, prevent default browser behavior if (button != 0 || ctrlKey || metaKey) {
if (!isString(this.target) || this.target == '_self') { return true;
this._router.navigate(this._commands, this._routeSegment);
return false;
} }
return true;
if (isString(this.target) && this.target != '_self') {
return true;
}
this._router.navigate(this._commands, this._routeSegment);
return false;
} }
private _updateTargetUrlAndHref(): void { private _updateTargetUrlAndHref(): void {
let tree = this._router.createUrlTree(this._commands, this._routeSegment); let tree = this._router.createUrlTree(this._commands, this._routeSegment);
if (isPresent(tree)) { if (isPresent(tree)) {
this.href = this._router.serializeUrl(tree); this.href = this._locationStrategy.prepareExternalUrl(this._router.serializeUrl(tree));
this.isActive = this._router.urlTree.contains(tree); this.isActive = this._router.urlTree.contains(tree);
} else { } else {
this.isActive = false; this.isActive = false;

View File

@ -26,8 +26,8 @@ import {
OnActivate, OnActivate,
CanDeactivate CanDeactivate
} from '@angular/router'; } from '@angular/router';
import {Location} from '@angular/common'; import {Location, LocationStrategy} from '@angular/common';
import {SpyLocation} from '@angular/common/testing'; import {SpyLocation, MockLocationStrategy} from '@angular/common/testing';
export function main() { export function main() {
describe('RouterLink', () => { describe('RouterLink', () => {
@ -35,6 +35,7 @@ export function main() {
provide(RouterUrlSerializer, {useClass: DefaultRouterUrlSerializer}), provide(RouterUrlSerializer, {useClass: DefaultRouterUrlSerializer}),
RouterOutletMap, RouterOutletMap,
provide(Location, {useClass: SpyLocation}), provide(Location, {useClass: SpyLocation}),
provide(LocationStrategy, {useClass: MockLocationStrategy}),
provide(Router, provide(Router,
{ {
useFactory: (resolver, urlParser, outletMap, location) => new Router( useFactory: (resolver, urlParser, outletMap, location) => new Router(
@ -44,14 +45,14 @@ export function main() {
]); ]);
describe("routerLink=", () => { describe("routerLink=", () => {
it("should accept an array of commands", inject([Router], (router) => { it("should accept an array of commands", inject([Router, LocationStrategy], (router, locationStrategy) => {
let link = new RouterLink(null, router); let link = new RouterLink(null, router, locationStrategy);
link.routerLink = ['/one', 11]; link.routerLink = ['/one', 11];
expect(link.href).toEqual("/one/11"); expect(link.href).toEqual("/one/11");
})); }));
it("should accept a single command", inject([Router], (router) => { it("should accept a single command", inject([Router, LocationStrategy], (router, locationStrategy) => {
let link = new RouterLink(null, router); let link = new RouterLink(null, router, locationStrategy);
link.routerLink = '/one/11'; link.routerLink = '/one/11';
expect(link.href).toEqual("/one/11"); expect(link.href).toEqual("/one/11");
})); }));
@ -61,4 +62,4 @@ export function main() {
@Component({template: ''}) @Component({template: ''})
class RootCmp { class RootCmp {
} }