Conditionally add target="_blank" to links with Angular JS
Asked Answered
M

4

38

I am building a navigation tree in Angular JS. Most links in the tree will point to pages within my website, but some may point to external sites.

If the href of a link begins with http:// or https:// then I am assuming the link is for an external site (a regex like /^https?:\/\// does the trick).

I would like to apply the target="_blank" attribute to these links. I was hoping to do this with angular when I am creating my links:

<ul>
    <li ng-repeat="link in navigation">
        <a ng-href="{{link.href}}" [add target="_blank" if link.href matches /^https?:\/\//]>{{link.title}}</a>
    </li>
</ul>

Can anyone help me out?

Thanks

Macaw answered 10/5, 2014 at 17:29 Comment(8)
Don't actually do this. It is bad from a UI point of view. Lets users decide when to open new windows or tabs.Roil
I know what you mean, but if the user is on the website and wants to click a link to an external resource, it makes sense to open the link in a new tab / window rather than redirecting their current tab. I use it sparingly and only when I think that being directed away from the site without it's tab staying open would be irritating / confusing for some users.Macaw
no. If a user is on a website and wants to click a link then it makes sense to open in the same tab. If they want to open it in a new tab they will ctrl-click, or right click and say "open in new tab". DO NOT break web conventions.Roil
@BenGuest Web conventions? You have this idea right. I am willing to take the karma on this one.Calise
@GoodPerson - There certainly are scenarios in which this is good from a UX perspective. Our AngularJS project is a SPA. Users that tap/click links want to open the link without disrupting their work in the app. Opening in a new tab by default is an appropriate way to meet this need.Mattheus
Additionally, I think you may be accustomed to designing for tech-savvy users. :) Ctrl-clicking/right clicking is akin to black magic for our users, and on mobile, tap-and-hold is likewise foreign.Mattheus
@GoodPerson opening an external link within the current tab is a bad experience as the average user would not know to navigate with the back button. Spend 1 hour in a UAT session and tell me again "web conventions" must always be conformed to.Gilligan
@Gilligan I have spent time observing users. A big part of the problem is different sites providing different experiences (for example, some using _blank and others not) thus never letting people get properly trained on how things workRoil
S
80

I was just about to create a directive as suggested and then realised that all you actually need to do is this:

<a ng-attr-target="{{(condition) ? '_blank' : undefined}}">
  ...
</a>

ng-attr-xyz lets you dynamically create @xyz, and if the value is undefined no attribute is created -- just what we want.

Spencerspencerian answered 2/6, 2015 at 15:12 Comment(5)
this was a great simple solution for me. It conditionally writes the attribute which is what I needed in this case. Simple and I learned I can do this with pretty much any attribute. Thanks!Breechblock
nice one, this is just what I was after. wasn't looking forward to adding another directive for something so simple!Unrequited
See Angular Documentation for how it works.Psf
This question explains the use of ng-attr-.Psf
error NG8002: Can't bind to 'ng-attr-target' since it isn't a known property of 'a'.Isentropic
D
36

Update

Or use a directive:

module.directive('myTarget', function () {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
          var href = element.href;
          if(true) {  // replace with your condition
            element.attr("target", "_blank");
          }
        }
    };
});

Usage:

<a href="http://www.google.com" my-target>Link</a>

When you don't need to use this with Angular routing you can simply use this:

<a href="http://www.google.com" target="{{condition ? '_blank' : '_self'}}">Link</a>
Difference answered 10/5, 2014 at 17:47 Comment(3)
Im under the impression that target="_self" prevents the routeProvider from capturing the link change. See hereMacaw
@BenGuest correct, in this case you need a simple directiveDifference
Okay thanks. The directive was exactly what I wanted. I guess that any custom behaviour regarding html elements warrants creation of a directive.Macaw
R
5

The proposed solutions will only work with hard-coded hrefs. They will fail if they are interpolated because angular will not have done any interpolation when the directive is run. The following solution will work on interpolated hrefs, and is based on Javarome's solution:

yourModule.directive('a', function() {
  return {
    restrict: 'E',
    link: function(scope, elem, attrs) {
      attrs.$observe('href', function(){
        var a = elem[0];
        if (location.host.indexOf(a.hostname) !== 0)
          a.target = '_blank';
      }
    }
  }
}
Redundancy answered 17/11, 2014 at 14:54 Comment(0)
E
2

A more simple directive does not require changes in your HTML by handling all <a href="someUrl"> tags, and adding target="_blank" if someURL does not target the current host:

yourModule.directive('a', function() {
  return {
    restrict: 'E',
    link: function(scope, elem, attrs) {
      var a = elem[0];
      if (a.hostname != location.host)
         a.target = '_blank';
    }
  }
}
Esme answered 5/6, 2014 at 9:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.