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


Answers

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);
}
Question

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?




<h1 ng-attr-contenteditable="{{isTrue || undefined }}">{{content.title}}</h1>

will produce when isTrue=true : <h1 contenteditable="true">{{content.title}}</h1>

and when isTrue=false : <h1>{{content.title}}</h1>




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>



For input field validation you can do:

<input ng-model="discount" type="number" ng-attr-max="{{discountType == '%' ? 100 : undefined}}">

This will apply the attribute max to 100 only if discountType is defined as %




Regarding the accepted solution, the one posted by Ashley Davis, the method described still prints the attribute in the DOM, regardless of the fact that the value it has been assigned is undefined.

For example, on an input field setup with both an ng-model and a value attribute:

<input type="text" name="myInput" data-ng-attr-value="{{myValue}}" data-ng-model="myModel" />

Regardless of what's behind myValue, the value attribute still gets printed in the DOM, thus, interpreted. Ng-model then, becomes overridden.

A bit unpleasant, but using ng-if does the trick:

<input type="text" name="myInput" data-ng-if="value" data-ng-attr-value="{{myValue}}" data-ng-model="myModel" />
<input type="text" name="myInput" data-ng-if="!value" data-ng-model="myModel" />

I would recommend using a more detailed check inside the ng-if directives :)