caitlin
caitlin

Reputation: 2819

Opening Angular 6 links bound by [innerHTML] in a new tab

I have an Angular 6 app with a <div> that gets populated via an [innerHTML] binding. How can I apply target='_blank' to all the links inside this div?

What I've tried:

So far, I've tried creating a directive that wraps the div and, after change detection gets run, pulls up a list of child <a> tags and applies a target='_blank' attribute. So far, I have not been able to get ContentChildren to access any of the links: It just pulls up an empty list.

Does anyone have experience doing this, or is there a more elegant solution?

@Directive({
  selector: '[appExternalLink]'
})
export class ExternalLinkDirective implements AfterContentChecked, AfterViewChecked {

  @ContentChildren('a', {descendants: true}) links: QueryList<any>;


  @Input() appExternalLink: string;
  constructor() {
    console.log('HELLO FROM APPEXTERNALLINK');
  }

  ngAfterContentChecked() {
    console.log(this.links);
  }

}

Then, when binding the content:

<div appExternalLink>
  <div [innerHTML]="content"></div>
</div>

Upvotes: 6

Views: 3084

Answers (3)

caitlin
caitlin

Reputation: 2819

It turns out I was using the wrong approach trying to use ContentChildren.

With the below code, I was able to target all <a> tags in a div with the appExternalLink directive. Posting my solution so other people don't have to figure this out themselves:

  import { AfterViewChecked, Directive, ElementRef } from '@angular/core';

  @Directive({
    selector: '[appExternalLink]'
  })
  export class ExternalLinkDirective implements AfterViewChecked {
    constructor(private el: ElementRef) { }

    ngAfterViewChecked() {
      Array.from(this.el.nativeElement.querySelectorAll('a'))
        .forEach((el: any) => {
          el.setAttribute('target', '_blank');
        });
    }
  }

Upvotes: 8

Ryan Searle
Ryan Searle

Reputation: 1627

This is the selector you're using

@ContentChildren('a', {descendants: true}) links: QueryList<any>;

What this does is look for any direct children of the component which have an id of a.

If you change your html to look like this:

<div appExternalLink>
    <a #a>Link</>
    <a #a>Link</>
</div>

Then your selector will find the links.

Upvotes: 1

Christian Vincenzo Traina
Christian Vincenzo Traina

Reputation: 10384

You can use the <base> tag to default the target attribute of each anchor.

<base target="_blank">

You can inject this tag dynamically in ngOnInit and remove it in ngOnDestroy, but it will change the behaviour of any link.

If you want to change the behaviour of just the anchors inside a div, you can use

Array.from(document.querySelectorAll('.your-div-class a'))
  .forEach(el => el.setAttribute('target', '_blank'))

Upvotes: 2

Related Questions