In Angular projects, it’s common to use [routerLink]
in template elements to handle navigation. While effective, this approach lacks the functionality of “Ctrl + Click” (or “Cmd + Click” on macOS) to open links in a new browser tab. In this post, I’ll share a simple yet effective directive to implement this feature.
Before you jump to the code, please note that this solution may not be what you’re looking for. If you’re dealing with <a>
tags then the default [routerLink]
is able to handle “Ctrl + Click” and open your content in a new tab. This directive is intended to be used in buttons, table rows, divs and other elements.
import {Directive, HostListener, Input} from '@angular/core';
import {Router, UrlSerializer} from '@angular/router';
@Directive({
selector: '[ctrlRouterLink]'
})
export class CtrlRouterLinkDirective {
@Input('ctrlRouterLink') routerLinkParts: string[] = [];
constructor(
private router: Router,
private urlSerializer: UrlSerializer
) {
}
@HostListener('click', ['$event'])
handleClick(event: MouseEvent): void {
this.navigate(event.ctrlKey, this.routerLinkParts);
}
navigate(inNewWindow = false, routerLinkParts: string[], routerLinkFragment?: string): void {
if (inNewWindow) {
const tree = this.router.createUrlTree(routerLinkParts);
let fullUrl = this.urlSerializer.serialize(tree);
if (routerLinkFragment) {
fullUrl += '#' + routerLinkFragment;
}
window.open(fullUrl, '_blank');
return;
}
this.router.navigate(routerLinkParts, { fragment: routerLinkFragment });
}
}
The directive can be used in your templates as a simple drop-in replacement for traditional [routerLink]
:
<tr *ngFor="let item of items" [ctrlRouterLink]="['/', 'target', single.id]">
It may also be injected into a component and called if required. This is useful when more complex for URL generation is required:
constructor(
private ctrlRouterLinkDirective: CtrlRouterLinkDirective
(...)
someEvent($event, item) {
(...)
this.ctrlRouterLinkDirective.navigate($event.ctrlKey, ['/', 'target', item.id],
}
That’s it!