What is the best way to conditionally apply attributes in AngularJS?

290,918

Solution 1

I am using the following to conditionally set the class attr when ng-class can't be used (for example when styling SVG):

ng-attr-class="{{someBoolean && 'class-when-true' || 'class-when-false' }}"

The same approach should work for other attribute types.

(I think you need to be on latest unstable Angular to use ng-attr-, I'm currently on 1.1.4)

Solution 2

You can prefix attributes with ng-attr to eval an Angular expression. When the result of the expressions undefined this removes the value from the attribute.

<a ng-attr-href="{{value || undefined}}">Hello World</a>

Will produce (when value is false)

<a ng-attr-href="{{value || undefined}}" href>Hello World</a>

So don't use false because that will produce the word "false" as the value.

<a ng-attr-href="{{value || false}}" href="false">Hello World</a>

When using this trick in a directive. The attributes for the directive will be false if they are missing a value.

For example, the above would be false.

function post($scope, $el, $attr) {
      var url = $attr['href'] || false;
      alert(url === false);
}

Solution 3

I got this working by hard setting the attribute. And controlling the attribute applicability using the boolean value for the attribute.

Here is the code snippet:

<div contenteditable="{{ condition ? 'true' : 'false'}}"></div>

I hope this helps.

Solution 4

In the latest version of Angular (1.1.5), they have included a conditional directive called ngIf. It is different from ngShow and ngHide in that the elements aren't hidden, but not included in the DOM at all. They are very useful for components which are costly to create but aren't used:

<h1 ng-if="editMode" contenteditable=true>{{content.title}}</h1>

Solution 5

To get an attribute to show a specific value based on a boolean check, or be omitted entirely if the boolean check failed, I used the following:

ng-attr-example="{{params.type == 'test' ? 'itWasTest' : undefined }}"

Example usage:

<div ng-attr-class="{{params.type == 'test' ? 'itWasTest' : undefined }}">

Would output <div class="itWasTest"> or <div> based on the value of params.type

Share:
290,918

Related videos on Youtube

Kenneth Lynne
Author by

Kenneth Lynne

Systems Consultant and web-fanatic from Norway

Updated on January 25, 2020

Comments

  • Kenneth Lynne
    Kenneth Lynne over 4 years

    I need to be able to add for example "contenteditable" to elements, based on a boolean variable on scope.

    Example use:

    <h1 attrs="{'contenteditable=\"true\"': editMode}">{{content.title}}</h1>
    

    Would result in contenteditable=true being added to the element if $scope.editMode was set to true. Is there some easy way to implement this ng-class like attribute behavior? I'm considering writing a directive and sharing if not.

    Edit: I can see that there seems to be some similarities between my proposed attrs directive and ng-bind-attrs, but it was removed in 1.0.0.rc3, why so?

    • Xesued
      Xesued over 11 years
      I haven't come across anything like that. I vote do it! :D Maybe submit it to the angular project. A syntax that better matches the ng-class would be nice. ng-attr="expression".
    • Kenneth Lynne
      Kenneth Lynne over 11 years
      I'm definately considering that yes!
    • Josh David Miller
      Josh David Miller over 11 years
      This really isn't the same as ngClass or ngStyle because they control a single attribute and you want to control any attribute. I think it would be better to create a contentEditable directive.
    • Umur Kontacı
      Umur Kontacı over 11 years
      @JoshDavidMiller +1 on that. I think there is a little benefit to be able to control any attribute, especially considering the complexity. You can have directives conditionally acting on a variable.
    • mia
      mia over 9 years
      <h1 ng-attr-contenteditable="{{editMode && true : false}}">{{content.title}}</h1>
    • Sanjay Singh
      Sanjay Singh almost 6 years
      In case you can here looking for Angular 2+ then just do following e.g. <input [readonly]="mode=='VIEW'">
    • NeverGiveUp161
      NeverGiveUp161 almost 6 years
      @JoshDavidMiller: how a directive will conditionally apply? can you explain? and am asking for attribute directive.
  • zonabi
    zonabi almost 11 years
    you can also use this method with things other than booleans, like checking if a variable is set to something certain. code class="{{varToCheck=='valueToCheck' && 'class-if-true' || 'class-if-false' }}" code
  • Matthias
    Matthias over 10 years
    Just to clarify this answer: If you prefix any attribute with ng-attr-, then the compiler will strip the prefix, and add the attribute with its value bound to the result of the angular expression from the original attribute value.
  • romu
    romu over 10 years
    I have published an article on working with Angular+SVG that covers many such issues. codeproject.com/Articles/709340/…
  • Max Strater
    Max Strater over 10 years
    I believe ng-if only works on an element level, that is, you can't specify a conditional to just one attribute of an element.
  • dshap
    dshap about 10 years
    In my opinion it's easier to read if you use a ternary operator, for which support was added in 1.1.5. That would look like: {{ someConditionalExpression ? 'class-when-true' : 'class-when-false' }}
  • airtonix
    airtonix about 10 years
    the problem with this approach is that the attribute gets created regardless of the outcome. Ideally we'd like control wether or not the attribute gets created at all.
  • Byscripts
    Byscripts about 10 years
    Indeed, but you can then do <h1 ng-if="editMode" contenteditable="true"><h1 ng-if="!editMode">
  • Shimon Rachlenko
    Shimon Rachlenko about 10 years
    beware, however, that ng-if creates a new scope.
  • Brian Genisio
    Brian Genisio about 10 years
    @ShimonRachlenko Agreed! This can be a big source of confusion and bugs. ng-if creates a new scope but ng-show does not. This inconsistency has always been a sore spot for me. The defensive programming reaction to this is: "always bind to something that a dot in the expression" and it won't be an issue.
  • Kalyan
    Kalyan almost 10 years
    With this approach, you will be repeating the same code though.
  • alexc
    alexc almost 10 years
    True, but it keeps the model declaration safe. My problem with using the accepted solution was that the value attribute ended up in the DOM, taking precedence over the model declaration. So, if the value attribute is empty but the model is not, the model will be overridden to take an empty value.
  • Roman K
    Roman K over 9 years
    I like this answer. However, I don't think if value is undefined it will hide the attribute. I might be missing something, though. So the first result would be <a ng-attr-href="{{value || undefined}}" href>Hello World</a>
  • Reactgular
    Reactgular over 9 years
    @RomanK hi, the manual states that undefined is a special case. "When using ngAttr, the allOrNothing flag of $interpolate is used, so if any expression in the interpolated string results in undefined, the attribute is removed and not added to the element."
  • Adam Marshall
    Adam Marshall over 9 years
    Just a note to aid any future readers, the 'undefined' behaviour appears to have been added in Angular 1.3. I am using 1.2.27 and currently must IE8.
  • Adam Marshall
    Adam Marshall over 9 years
    NOTE: this does not work with directives that are classes, as it doesn't get re-compiled
  • Adam Marshall
    Adam Marshall over 9 years
    If you want to add an attribute that is actually a directive, this works great. Shame about the code duplication
  • Judah Gabriel Himango
    Judah Gabriel Himango over 9 years
    Note that the ng-attr- stuff was removed from Angular 1.2. This ansswer is no longer valid.
  • romu
    romu over 9 years
    You are wrong. This project github.com/codecapers/AngularJS-FlowChart uses Angular 1.2 and ng-attr-. Also the latest docs (Angular 1.4) still include ng-attr-
  • Brian Ogden
    Brian Ogden over 9 years
    To confirm some more Angular 1.2.15 will display href even if value is undefined, looks like the undefined behavior starts in Angular 1.3 as the above comment states.
  • SuperUberDuper
    SuperUberDuper about 9 years
    what if I want some thing like <h1 contenteditable="row">
  • mccainz
    mccainz almost 9 years
    As angular can parse the IIF expression this works perfectly for evaluating state in the current scope and assiging values based on that state.
  • dr_leevsey
    dr_leevsey over 8 years
    it works, yeah!!! but is extremely slow. Do not use it for ng-repeat'ed elements!
  • romu
    romu over 8 years
    Ha, this is probably old advice now. Then it seem the best way to style SVG, but AngularJS may have changed in the meantime! There might be a better way now.
  • Splaktar
    Splaktar almost 8 years
    ng-attr wasn't really removed. It was just refactored. The start of the new implementation is here: github.com/angular/angular.js/commit/…
  • hughes
    hughes over 7 years
    It's important to note that ng-attr-foo will still always invoke the foo directive if it exists, even ng-attr-foo evaluates to undefined. discussion
  • Greg
    Greg almost 7 years
    This worked for me. I was trying to conditionally produce attributes for Bootstrap, and ng-attr would not work for me because Bootstrap finished its processing before Angular did. There may be a way to get Bootstrap to run after Angular, and this solution creates twice as much code, but it works great.
  • zendu
    zendu over 6 years
    Apparently it seems to be bad practice. docs.angularjs.org/…
  • PhatBuck
    PhatBuck over 6 years
    <h1 ng-attr-contenteditable="{{isTrue ? 'row' : undefined}}">{{content.title}} </h1>
  • Tauri28
    Tauri28 over 6 years
    Not working for multiple attribute on select element. More info here stackoverflow.com/questions/43272960/…
  • LucasM
    LucasM almost 6 years
    This should me be the accepted answer. My scenario was <video ng-attr-autoplay="{{vm.autoplay || undefined}}" />
  • ssc-hrep3
    ssc-hrep3 about 5 years
    Angular.JS is Angular 1, which is very different from Angular 2+. Your solution answers for Angular 2+, but AngularJS (1) was asked for.
  • Zaphoid
    Zaphoid about 5 years
    @ssc-hrep3: You are right. Sorry I missed that! Thanks. I edited the answer to point that out. :-)
  • dgzornoza
    dgzornoza over 4 years
    is angularjs not angular, angularjs is angular 1
  • dgzornoza
    dgzornoza over 4 years
    is angularjs (angular1) not angular (angular2)
  • Sanjay Singh
    Sanjay Singh about 4 years
    angular 2+ and Angular JS are not same, they are more like different products altogether.