8

so I write this small app where I show some information fetched from Wikipedia. There are also links inside of this fetched HTML.

So what I want to do:

Every time the user clicks on a link I want to intercept this and do custom behavior instead of the default browser redirect.

The build in Angular httpinterceptor is not working here. How do I get this effect?

CODE:

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class HttpInterceptorService implements HttpInterceptor {

  constructor() {

  }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { //HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
    console.assert(true, 'Intercepting Link request!' + request.url);
    return next.handle(request);
  }
}

Do I misunderstand something perhaps?

EDIT: seems like I misunderstood how the href and http requests work. Still I want to do custom behaviour on every link clicked on my application. Is there no possible way to intercept those "events"?

Adriaan
  • 17,741
  • 7
  • 42
  • 75
rufreakde
  • 542
  • 4
  • 17
  • Why *would* the HttpInterceptor work? That's for when your application makes requests to external web services, it's nothing to do with navigation within, to or from your app. Just implement a `click` binding on the elements rather than an `href`. – jonrsharpe Oct 04 '17 at 08:15
  • Did you read that i fetch everything from Wikipedia? So I get the links from them but I don't want to navigate a link but still want to do custom behavior with them? I understand that the Http intercept was wrong but how do I achieve it? – rufreakde Oct 04 '17 at 08:18

4 Answers4

13

Okay after searching a little longer I found a "not angular" solution: Override default behaviour for link ('a') objects in Javascript

And so I created a service out of this and injected it in my App Root component.

import { Injectable } from '@angular/core';

@Injectable() export class HrefInterceptorService {

    constructor() {
        document.onclick = this.interceptHref;
    }

    interceptHref(_event) {
        const tEvent = _event || window.event;

        const element = tEvent.target || tEvent.srcElement;

        if (element.tagName === 'A') {

            console.log("intercept!");

            return false; // prevent default action and stop event propagation
        }
    } }

Its a little hacky but relatively flexible.

rufreakde
  • 542
  • 4
  • 17
  • This worked somewhat for me but was not sufficient. In following question https://stackoverflow.com/questions/41458842/attaching-click-to-anchor-tag-in-angular2?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa I found that the question was actually the solution for me. If anyone looking into intercepting the anchor tag I think this question link is actually a good solution – Nicholas Jun 11 '18 at 11:51
  • strange it should work depending on the browser. I used chrome. You might change the 'A' to 'a' or add some new. Also this was in Angular version 2.x did not test it in 4.x! – rufreakde Jun 22 '18 at 17:23
3

I needed to track outbound clicks for analytics purposes with pages that were built with [innerhtml] as well. I tried a bunch of things, but the answer turned out to be really simple. I only need to check a couple of levels up parents for the appropriate link element:

public hrefClicked( $event )
{
  let targetElement;

  if( ( $event.srcElement.nodeName.toUpperCase() === 'A') )
      targetElement = $event.srcElement;
  else if( $event.srcElement.parentElement.nodeName.toUpperCase() === 'A' )
      targetElement = $event.srcElement.parentElement;
  else
      return;

  //  console.log( "Found LINK:" );
  //  console.log( targetElement.href );

  if( targetElement.href && !targetElement.href.includes("mydomain"))
    {
     console.log( "OUTBOUND LINK:" + $event.srcElement.href );
    }
 }
<div class="container-fluid" (click)="hrefClicked($event)">
  <div class="row">
    <div class="col-xs-12">
      <div class="article-body" [innerHTML]="article.content"></div>
    </div>
  </div>
</div>  
Jolly
  • 349
  • 1
  • 2
  • 9
2

Loading a new page is not an XHR request. So interceptors can't work. You need to capture the click event and prevent propagation:

template:

<a href="//example.com" (click)="myHandler($event)">Click me</a>

component:

myHandler(event){
  event.preventDefault();

  doSomethingElse();
}
j2L4e
  • 6,914
  • 34
  • 40
  • Thanks for your reply, but do I have to parse all the HTML from wikipedia I fetch just to do so? Seems I misunderstood this: https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Intercept_HTTP_requests – rufreakde Oct 04 '17 at 08:24
1

I found a more angular solution for this using @HostListener, for intercepting links that open a new tab

DOCS: https://angular.io/api/core/HostListener#description

With this more angular oriented implementation you can access the this from the angular controller instead the DOC using native methods

This is the implementation

  @HostListener('document:click', ['$event'])
  clickout(_event: Event): boolean {
    const event = _event || window.event;
    const element = event.target || event.srcElement;
    // check for links with target "_blank"
    if ('A' === element.tagName && '_blank' === element.target) {
      // do your stuff here with access to the controller methods
      this.myStuff();
      // prevent default action and stop event propagation
      event.stopPropagation();
      event.preventDefault();
      return false;
    }
  }
  
  private myStuff() {
    console.log( "OUTBOUND LINK:" + element.href );
    // open the link in a new TAB
    window.open(element.href, '_blank')
  }
ppollono
  • 3,421
  • 1
  • 19
  • 29