0

This is for an Angular 5 / Ionic 3 application. I have a div where I display user generated html from a rich text editor:

<div [innerHtml]='text'></div>

This data can include <a href> links for which I need to capture the click event in order to force opening in the system's default browser.

I made a directive that works flawlessly for static content but will not affect anything inside the innerHtml element.

import { Directive, Input, HostListener } from "@angular/core";
import { InAppBrowser } from "@ionic-native/in-app-browser";

@Directive({
  selector : '[href]'
})
export class PreventLink {

  @Input() href;

  constructor( private iab: InAppBrowser ) {};

  @HostListener('click', ['$event'])
  public onClick( event: Event ) {

    if( event && this.href ) {

      if( this.href.length > 0 ){
        this.iab.create( this.href, '_system' );
      }

      event.preventDefault();
      return false;
    }
  };
};

Any ideas to achieve what I need would be appreciated.

Jahrenski
  • 171
  • 4
  • 20

2 Answers2

1

I will post here my hacky solution if anyone wondered how to do it. I am still hoping for a better and more "angular" solution to achieve this.

First we need to prepare a basic javascript snippet in index.html to find out when anchors are clicked. Place this at the end of the section.

<script>
  document.onclick = function (e){
    e = e || window.event || {};
    var element = e.target || e.srcElement;

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

      handleAClick( element.href );

      e.preventDefault();
      return false;
    }
  };

  function handleAClick(){}; //Just a placeholder until the angular app is ready
</script>

Then in app.component.ts I will override the handleAClick function with the real deal:

import { Component, OnInit, ViewChild } from '@angular/core';
import { InAppBrowser } from '@ionic-native/in-app-browser';
import { Platform } from 'ionic-angular';


@Component({
  templateUrl: 'app.html'
})

export class MySuperApp implements OnInit {

  constructor( private platform: Platform, private iab: InAppBrowser ){};

  ngOnInit() {

    this.platform.ready().then( () => {

      let win = (<any>window);
      win.handleAClick = ( url: string ) => {
        this.handleAClick( url );
      };
    });
  };


  private handleAClick( href: string ) {

    if( href && href.length > 0 ) {
      this.iab.create( href, '_system' );
    }
  };
};
Jahrenski
  • 171
  • 4
  • 20
1

This post is pretty old but if anyone else comes across this I solved it using a nearly identical custom directive, this setup is confirmed working for me using angular 9 / ionic 5.

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

/**
 * Custom directive so that we can listen for clicks (or taps) on the event detail page.
 * When the user clicks on an embeded link it will be opened by the browser service and now what ever target
 * the link was written for.
 * Since we dont control the content of the event feed descriptions this is the only way we can control
 * what happens when they include a link and the user opens it.
 */
@Directive({
    selector: '[linkInterceptor]',
})
export class LinkIntereptorDirective {

    @HostListener('click', ['$event']) onClick(event: any) {
        this.clickJack(event);
    }

    @HostListener('tap', ['$event']) onTap(event: any) {
        this.clickJack(event);
    }

    private clickJack(event) {
        event.preventDefault();
        if (event.target.tagName.toLowerCase() === 'a') {
            this.open(event.target.href);
        }
    }

    private async open(href) {
        // here you can handle how you want to open the url.
    }

    constructor() { }
}

Template:

<div *ngIf="content.length" class="ion-padding-horizontal" tappable linkInterceptor [innerHtml]="getHtml()"></div>

Component:

  /**
   * For somereason on ionic when you use the pipe syntax to sanitize
   * html it makes the content block not clickable. So this fixes that so we can register our custom link interceptor directive.
   */
  getHtml(): SafeHtml {
    return this.domSanitizer.sanitize(SecurityContext.HTML, htmlContent);
  }
DerrickF
  • 682
  • 5
  • 9