Open all links using system browser inside an ionic app

Because the HTML is already rendered when it comes to Angular, and the inAppBrowser plugin only works if called by explicit Javascript, there is nothing you can do that doesn't involve manually changing the HTML or using plain javascript.

Changing the HTML is just a Bad Idea®, especially if you try to do it by using regex matching.

That leaves javascript:

Restangular.all('stories').getList().then(function(stories){
  $scope.stories = stories;
  updateLinks();
});

function updateLinks(){
  //use $timeout wait for items to be rendered before looking for links
  $timeout(function(){
      var $links = document.querySelectorAll(".stories .story a");
      for(var i =0; i < $links.length; i++) {
        var $link = $links[i];
        var href = $link.href;
        console.log("Hijacking link to ", href);
        $link.onclick = function(e){
          e.preventDefault();
          var url = e.currentTarget.getAttribute("href");
          window.cordova.inAppBrowser.open(url, "_system");
        }
      }
    });
}

Install next plugin:

cordova plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-inappbrowser.git

Now, you can use _system, _blank or _self for destination:

window.open(url, '_blank');

More info: https://www.thepolyglotdeveloper.com/2014/07/launch-external-urls-ionicframework/


AFAIK there isn't a way of doing that automatically, you must use the in app browser js code to open links externally consistently in every platform.

Your question doesn't give a clear example of what the server returns so I'm assuming you are getting a full block of html and are just rendering it on the screen. Assuming a request return something basic like :

<div id="my-links">
   <a href='http://externallink.com'> External Link 1 </a>
   <a href='http://externallink.com'> External Link 2 </a>
   <a href='http://externallink.com'> External Link 3 </a>
</div>

And your request looks like:

$http.get('givemelinks').success(function(htmlData){
   $scope.myContent = htmlData;
})

If you have access to the server side and can make changes:

Add a "inappbrowser" parameter to your request to detect if it should return inappbrowser compatible links and change the response from your server to be something like:

if (inappbrowser) {
<div id="my-links">
   <div ng-click='openExternal($event)' data-external='http://externallink.com'> External Link 1 </div>
   <div ng-click='openExternal($event)' data-external='http://externallink.com'> External Link 2 </div>
   <div ng-click='openExternal($event)' data-external='http://externallink.com'> External Link 3 </div>
</div>
} else {
 <div id="my-links">
   <a href='http://externallink.com'> External Link 1 </a>
   <a href='http://externallink.com'> External Link 2 </a>
   <a href='http://externallink.com'> External Link 3 </a>
</div>
}

And have a generic openExternal method:

$scope.openExternal = function($event){
  if ($event.currentTarget && $event.currentTarget.attributes['data-external'])
  window.open($event.currentTarget.attributes['data-external'], '_blank', 'location=yes');
}

If you can't change the server side

Parse the response and replace the links with ng-clicks:

$http.get('givemelinks').success(function(htmlData){
   htmlData = htmlData.replace(/href='(.*)'/,'ng-click="openExternal($event)" data-external="$1"').replace(/<a/,"<div").replace(/a>/,"div>")
   $scope.myContent = htmlData;
})

And use the same openExternal method as above.

I'm replacing the anchors with divs to prevent changing the app routes. That might not be necessary in every app.

To make this even better you should bundle it in a open-external directive so you can use it in multiple controllers and keep them cleaner.