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

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. Commented May 10, 2014 at 18:23
  • 10
    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. Commented May 10, 2014 at 19:33
  • 1
    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. Commented May 10, 2014 at 19:34
  • 9
    @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. Commented Jan 27, 2017 at 17:36
  • 1
    @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. Commented May 13, 2019 at 14:27

4 Answers 4

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.

Sign up to request clarification or add additional context in comments.

5 Comments

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!
nice one, this is just what I was after. wasn't looking forward to adding another directive for something so simple!
See Angular Documentation for how it works.
This question explains the use of ng-attr-.
error NG8002: Can't bind to 'ng-attr-target' since it isn't a known property of 'a'.
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>

3 Comments

Im under the impression that target="_self" prevents the routeProvider from capturing the link change. See here
@BenGuest correct, in this case you need a simple directive
Okay thanks. The directive was exactly what I wanted. I guess that any custom behaviour regarding html elements warrants creation of a directive.
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';
      }
    }
  }
}

Comments

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';
    }
  }
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.