Skip to content

Commit

Permalink
feat(directives): Added linkTo directive
Browse files Browse the repository at this point in the history
  • Loading branch information
brandonroberts committed Apr 1, 2016
1 parent fc5d39e commit 7703ba2
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 3 deletions.
5 changes: 4 additions & 1 deletion lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { GUARD_PROVIDERS } from './guard';
import { MATCH_ROUTE_PROVIDERS } from './match-route';
import { COMPONENT_RENDERER_PROVIDERS } from './component-renderer';
import { QUERY_PARAMS_PROVIDERS } from './query-params';
import { LINK_TO_PROVIDERS } from './link-to';

export function provideRouter(routes: Routes) {
return [
Expand All @@ -25,7 +26,8 @@ export function provideRouter(routes: Routes) {
GUARD_PROVIDERS,
MATCH_ROUTE_PROVIDERS,
COMPONENT_RENDERER_PROVIDERS,
QUERY_PARAMS_PROVIDERS
QUERY_PARAMS_PROVIDERS,
LINK_TO_PROVIDERS
];
}

Expand All @@ -39,3 +41,4 @@ export { usePreRenderMiddleware, usePostRenderMiddleware, RenderInstruction } fr
export { Routes, Route, IndexRoute } from './route';
export { useTraversalMiddleware } from './match-route';
export { QueryParams } from './query-params';
export { LinkTo } from './link-to';
73 changes: 73 additions & 0 deletions lib/link-to.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import {
Directive,
HostBinding,
HostListener,
Input,
PLATFORM_DIRECTIVES,
provide,
Provider
} from 'angular2/core';
import { Location } from './location';

/**
* The LinkTo directive links to routes in your app
*
* Links are pushed to the `Location` service to trigger a route change.
* Query params can be represented as an object or a string of names/values
*
* <a linkTo="/home/page" [queryParams]="{ id: 123 }">Home Page</a>
* <a [linkTo]="'/pages' + page.id">Page 1</a>
*/
@Directive({ selector: '[linkTo]' })
export class LinkTo {
@Input() target: string;
@HostBinding('attr.href') linkHref;

@Input() set linkTo(href: string){
this._href = href;
this._updateHref();
}

@Input() set queryParams(params: string | Object) {
this._query = params;
this._updateHref();
}

private _href: string;
private _query: string | Object;

constructor(private _location: Location) {}

/**
* Handles click events on the associated link
* Prevents default action for non-combination click events without a target
*/
@HostListener('click', ['$event'])
onClick(event) {
if (!this._comboClick(event) && !this.target) {
this._location.go(this._href, this._query);

event.preventDefault();
}
}

private _updateHref() {
this.linkHref = this._location.prepareExternalUrl(this._href, this._query);
}

/**
* Determines whether the click event happened with a combination of other keys
*/
private _comboClick(event) {
let buttonEvent = event.which || event.button;

return (buttonEvent > 1 || event.ctrlKey || event.metaKey || event.shiftKey);
}
}

export const LINK_TO_PROVIDERS = [
provide(PLATFORM_DIRECTIVES, {
multi: true,
useValue: [ LinkTo ]
})
];
8 changes: 6 additions & 2 deletions lib/location.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,11 @@ export class Location extends ReplaySubject<LocationChange>{
* before normalizing. This method will also add a hash if `HashLocationStrategy` is
* used, or the `APP_BASE_HREF` if the `PathLocationStrategy` is in use.
*/
prepareExternalUrl(url: string): string {
prepareExternalUrl(url: string, query: any = ''): string {
if (url.length > 0 && !url.startsWith('/')) {
url = '/' + url;
}
return this.platformStrategy.prepareExternalUrl(url);
return this.platformStrategy.prepareExternalUrl(url + normalizeQueryParams(normalizeQuery(query)));
}

/**
Expand Down Expand Up @@ -161,6 +161,10 @@ function normalizeQuery(query: any) {
return typeof query === 'string' ? query : stringifyQueryParams(query);
}

function normalizeQueryParams(params: string): string {
return (params.length > 0 && params.substring(0, 1) != '?') ? ('?' + params) : params;
}

export const LOCATION_PROVIDERS = [
provide(Location, { useClass: Location }),
provide(PlatformLocation, { useClass: BrowserPlatformLocation })
Expand Down

0 comments on commit 7703ba2

Please sign in to comment.