Last active
July 11, 2019 11:55
-
-
Save iffa/d8361fb00f5885a050806159cb70031d to your computer and use it in GitHub Desktop.
Modified RouterLinkWithHref directive for Angular, that triggers normally for new tab/window but emits an event for normal left click. For cases where you need custom logic only when staying on the current open tab. Tested with Angular 6+
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { ActivatedRoute, NavigationEnd, Router, RouterEvent, RouterLinkWithHref, UrlTree } from '@angular/router'; | |
import { | |
Directive, | |
EventEmitter, | |
HostBinding, | |
HostListener, | |
Input, | |
isDevMode, | |
OnChanges, | |
OnDestroy, | |
Output | |
} from '@angular/core'; | |
import { QueryParamsHandling } from '@angular/router/src/config'; | |
import { Subscription } from 'rxjs'; | |
import { LocationStrategy } from '@angular/common'; | |
/** | |
* Modified {@link RouterLinkWithHref} directive that only triggers navigation if the result of the click event would result | |
* in the route being opened in a new tab or window. Simple left-clicking does nothing, so (leftClickEvent) can be used | |
* in case you need custom logic when staying in the existing tab. | |
* | |
* Add this directive to a module's declarations to use it in components. | |
* | |
* Derived from: https://github.com/angular/angular/blob/8.0.0/packages/router/src/directives/router_link.ts (tag 8.0.0) | |
*/ | |
@Directive({ | |
selector: 'a[appNewTabRouterLink],area[appNewTabRouterLink]' | |
}) | |
export class NewTabRouterLinkDirective implements OnChanges, OnDestroy { | |
@HostBinding('attr.target') @Input() target !: string; | |
@Input() queryParams: { [k: string]: any }; | |
@Input() fragment: string; | |
@Input() queryParamsHandling: QueryParamsHandling; | |
@Input() preserveFragment: boolean; | |
@Input() skipLocationChange: boolean; | |
@Input() replaceUrl: boolean; | |
@Input() state?: { [k: string]: any }; | |
private commands: any[] = []; | |
private subscription: Subscription; | |
private preserve: boolean; | |
// the url displayed on the anchor element | |
@HostBinding() href: string; | |
// called when it is just a left click | |
@Output() leftClickEvent = new EventEmitter(); | |
constructor( | |
private router: Router, private route: ActivatedRoute, | |
private locationStrategy: LocationStrategy) { | |
this.subscription = router.events.subscribe((s: RouterEvent) => { | |
if (s instanceof NavigationEnd) { | |
this.updateTargetUrlAndHref(); | |
} | |
}); | |
} | |
@Input() | |
set appNewTabRouterLink(commands: any[] | string) { | |
if (commands != null) { | |
this.commands = Array.isArray(commands) ? commands : [commands]; | |
} else { | |
this.commands = []; | |
} | |
} | |
@Input() | |
set preserveQueryParams(value: boolean) { | |
if (isDevMode() && <any>console && <any>console.warn) { | |
console.warn('preserveQueryParams is deprecated, use queryParamsHandling instead.'); | |
} | |
this.preserve = value; | |
} | |
ngOnChanges(changes: {}): any { | |
this.updateTargetUrlAndHref(); | |
} | |
ngOnDestroy(): any { | |
this.subscription.unsubscribe(); | |
} | |
@HostListener('click', ['$event.button', '$event.ctrlKey', '$event.metaKey', '$event.shiftKey']) | |
onClick(button: number, ctrlKey: boolean, metaKey: boolean, shiftKey: boolean): boolean { | |
if (button !== 0 || ctrlKey || metaKey || shiftKey) { | |
return true; | |
} else if (typeof this.target === 'string' && this.target !== '_self') { | |
return true; | |
} else { | |
// Dispatch event if left click, passing event details for consistency | |
this.leftClickEvent.emit({ button, ctrlKey, metaKey, shiftKey }); | |
return false; | |
} | |
} | |
private updateTargetUrlAndHref(): void { | |
this.href = this.locationStrategy.prepareExternalUrl(this.router.serializeUrl(this.urlTree)); | |
} | |
get urlTree(): UrlTree { | |
return this.router.createUrlTree(this.commands, { | |
relativeTo: this.route, | |
queryParams: this.queryParams, | |
fragment: this.fragment, | |
preserveQueryParams: attrBoolValue(this.preserve), | |
queryParamsHandling: this.queryParamsHandling, | |
preserveFragment: attrBoolValue(this.preserveFragment), | |
}); | |
} | |
} | |
function attrBoolValue(s: any): boolean { | |
return s === '' || !!s; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment