Rendering hyperlinks from HTML strings in Ionic 4 and Angular

November 18, 2018, 12:56 pm Categories:

Categories

Over the course of the following tutorial I want to take you through how I solved a particular challenge I encountered in a recent Ionic development contract: rendering clickable hyperlinks from HTML strings and opening their URL's within the browser.

With this in mind we'll be using Ionic 4 to create the following Android application (you can build for iOS if that's your preferred platform):

Ionic 4 Android App displaying hyperlinks opening content within Ionic Native InAppBrowser plugin

NOTE: If you're a strict Angular fundamentalist you might well be offended by the use of DOM querying methods that are used in this tutorial - so be warned! :D

If you know of a 'cleaner', more Angular way of achieving the same functionality then let me know - I'm always open to learning new approaches :)

Creating our project

From the command line (and, remember, this WILL require Ionic 4) create the following Ionic project and, once completed, follow this up by installing the necessary platforms/plugins:

ionic start ionic-dynamic-links blank --type=angular
cd ionic-dynamic-links
ionic cordova platform add android
ionic cordova plugin add cordova-plugin-inappbrowser
npm install --save @ionic-native/in-app-browser@beta

As stated earlier we're only going to be targeting Android for this tutorial but if you want to use iOS instead then feel free to do so.

The Ionic Native InAppBrowser plugin will work on both platforms so you're covered either way.

Configuring the root module

As always we need to ensure that any installed plugins/libraries are imported into and declared in the relevant section(s) of our project's root module (otherwise the application might launch with a "white screen of death" or a similarly broken UI).

Open the ionic-dynamic-links/src/app/app.module.ts root module and ensure that the code contained within this file matches the following:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';

import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';
import { InAppBrowser } from '@ionic-native/in-app-browser/ngx';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
  providers: [
    StatusBar,
    SplashScreen,
    InAppBrowser,
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

With those in place we can now move onto defining the logic and templating for the application - beginning with the HomePage component class...

Scripting the logic

Our HomePage component class will be responsible for providing the embedded HTML string that contains our hyperlinks - amongst other HTML tags - as well as the logic for parsing these and allowing the user to click on them and open their respective URLs within the Ionic Native InAppBrowser plugin.

This is pretty straightforward as demonstrated within the following code of the ionic-dynamic-links/src/app/home/home.page.ts class (the associated comments should help guide your understanding at each step of the class):

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

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage implements OnInit {



   /**
    * Property that will store the selected hyperlink from the view template 
    * @private
    * @name _link
    * @type {string}
    */
   private _link : string;



   /**
    * HTML string that contains embedded hyperlinks (that we will be 'activating'
    * later on in the script)
    * @public
    * @name snippet
    * @type {string}
    */
   public snippet : string = `<h1>Top 5 tech companies</h1>
                              <ul>
                                 <li>
                                    <a href="http://www.apple.com">Apple</a>
                                 </li>
                                 <li>
                                    <a href="http://www.facebook.com">Facebook</a>
                                 </li>
                                 <li>
                                    <a href="http://www.google.com">Google</a>
                                 </li>
                                 <li>
                                    <a href="http://www.microsoft.com">Microsoft</a>
                                 </li>
                                 <li>
                                    <a href="http://www.twitter.com">Twitter</a>
                                 </li>
                              </ul>`;




   /**
    * Initialises the class with required dependencies
    * @constructs
    * @param {InAppBrowser}   _browser      Ionic Native InAppBrowser plugin module
    * @param {ElementRef}     _element      Angular ElementRef module
    */
   constructor(private _browser : InAppBrowser,
               private _element : ElementRef)
   {  }




   /**
    * Use Angular OnInit lifecycle hook to trigger functionality when the view is initialising
    * @public 
    * @method ngOnInit
    * @return {none}
    */
   public ngOnInit() : void
   {
      this._enableDynamicHyperlinks();
   }




   /**
    * Enable hyperlinks that are embedded within a HTML string
    * @private
    * @method _enableDynamicHyperlinks
    * @return {none}
    */
   private _enableDynamicHyperlinks() : void
   {
      // Provide a minor delay to allow the HTML to be rendered and 'found'
      // within the view template
      setTimeout(() => 
      {
         // Query the DOM to find ALL occurrences of the <a> hyperlink tag
         const urls : any    = this._element.nativeElement.querySelectorAll('a');

         // Iterate through these
         urls.forEach((url) => 
         {
            // Listen for a click event on each hyperlink found
            url.addEventListener('click', (event) => 
            {
               // Retrieve the href value from the selected hyperlink
               event.preventDefault();
               this._link = event.target.href;

               // Log values to the console and open the link within the InAppBrowser plugin
               console.log('Name is: ' + event.target.innerText);
               console.log('Link is: ' + this._link);
               this._launchInAppBrowser(this._link);
            }, false);
         });
      }, 2000);
   }



   /**
    * Creates/launches an Ionic Native InAppBrowser window to display hyperlink locations within 
    * @private
    * @method _launchInAppBrowser
    * @param {string}    link           The URL to visit within the InAppBrowser window 
    * @return {none}
    */
   private _launchInAppBrowser(link : string) : void
   {
      let opts : string = "location=yes,clearcache=yes,hidespinner=no"
      this._browser.create(link, '_blank', opts);
   }

}

Here, within the _enableDynamicHyperlinks method, we make use of Angular's ElementRef class (which allows direct DOM access - always seen as a method of last resort within Angular due to potential security risks as well as being frowned on due to tight coupling between the class and template) in order to help access the embedded HTML code and search for the presence of hyperlinks.

To accomplish this end we then make use of the DOM querySelectorAll method which returns a list of all matching elements which are subsequently iterated through before being assigned event listeners to handle user generated click events.

Within the event listener for the click event the href value from the hyperlink is extracted and passed to the _launchInAppBrowser() method to open that resource within the Ionic Native InAppBrowser plugin.

Fairly straightforward right?

All that remains now is to add the necessary HTML (which is very minimal) for the view template.

Open the ionic-dynamic-links/src/app/home/home.page.html template and add the following code:

<ion-header>
  <ion-toolbar>
    <ion-title>
      Dynamic hyperlinks
    </ion-title>
  </ion-toolbar>
</ion-header>

<ion-content padding>
   <div [innerHTML]="snippet"></div>
</ion-content>

It doesn't get much simpler than that does it? :D

Here we simply use an innerHTML property binding to properly render the HTML string for the snippet property (that we declared within the component class).

Now all that remains is to publish the application to our handheld device (which, for the purposes of this tutorial, will be an Android phone - don't forget to connect this to your computer!) using the following Ionic CLI command:

ionic cordova run android --prod --device

All of which should (always assuming no errors) result in the following application being published to and running on your Android device (the different screens demonstrate the Home page in its default view as well as the InAppBrowser plugin being activated and loading/displaying content from various links that have been clicked on):

Ionic 4 Android App displaying hyperlinks opening content within Ionic Native InAppBrowser plugin

In summary

Angular purists might frown on the above solution but I don't see any issues with directly accessing the DOM if that's the least painful and most effective approach to resolving a particularly tricky requirement.

Of course, if you know of a more Angular-centric approach to achieving the above (without accessing the DOM) then let me know!

If you've enjoyed what you've read and/or found this helpful please feel free to share your comments, thoughts and suggestions in the comments area below.

I explore different aspects of working with the Ionic 4 framework in my e-book featured below and if you're interested in learning more about further articles and e-books that I'm writing please sign up to my FREE mailing list.

Tags

Categories

Post a comment

All comments are welcome and the rules are simple - be nice and do NOT engage in trolling, spamming, abusiveness or illegal behaviour. If you fail to observe these rules you will be permanently banned from being able to comment.

Top