64

The knockout.js library has an "attr" data binding which allows you to dynamically change the value of an HTML element attribute (e.g. the "title"). However, in some cases, the attribute may or may not be needed depending on the corresponding observable on the bound object. For example, if my model has a "title" observable I might want to set the "title" attribute if it is present (non-null) or skip the attribute entirely if it is not present (null).

Does knockout provide any way to conditionally set an attribute? (Ideally without conditionally rendering the entire element opening tag...)

[Note] This similarly named question was actually resolved by knockout's special handling of CSS classes and does not relate to this question (or its own title): How to conditionally render an css class with knockoutjs

Community
  • 1
  • 1
maerics
  • 151,642
  • 46
  • 269
  • 291
  • 1
    I think that's the default behaviour if observable returns null but i can be wrong. May I ask you why do you need to explicitly don't set the attribute instead of title="" in case of an empty value ? – Bart Calixto Oct 18 '12 at 23:55

4 Answers4

100

I needed this when selecting an <option> (that I was generating manually instead of built-in knockout).

<option 
 data-bind="text: text, 
    attr:{
     value:value,
     'selected': typeof(selected) !== 'undefined' ? selected : null 
     }">
 Choice X
</option>

This says to always update the 'text' attribute and to add the 'value' attribute, but only add 'selected' if the the data already has a value of 'selected' defined.

Richard Parnaby-King
  • 14,703
  • 11
  • 69
  • 129
JJ Rohrer
  • 2,671
  • 5
  • 29
  • 37
  • 16
    so basically put 'null' as attribute value and it will not render attribute, nice! – root Aug 05 '13 at 13:44
  • 2
    This should be the validated answer. It perfectly answers the question in the most simple way. – Laurent S. Apr 08 '14 at 09:24
  • 1
    I agree that this should be the accepted answer. While creating a custom binding will absolutely work, this is simpler, and addresses the question asked more directly. – kiprainey Aug 18 '14 at 20:45
  • Very clean solution if your logic is simple. Up-vote. – pim Jun 19 '15 at 20:38
30

You can create a custom binding attrIf which will check the value of a specific observable boolean before add or not the attributes. See this example:

ko.bindingHandlers.attrIf = {
    update: function (element, valueAccessor, allBindingsAccessor) {
        var h = ko.utils.unwrapObservable(valueAccessor());
        var show = ko.utils.unwrapObservable(h._if);
        if (show) {
            ko.bindingHandlers.attr.update(element, valueAccessor, allBindingsAccessor);
        } else {
            for (var k in h) {
                if (h.hasOwnProperty(k) && k.indexOf("_") !== 0) {
                    $(element).removeAttr(k);
                }
            }
        }
    }
};

<a href="#" data-bind="attrIf: {title: title, _if: flag}">link</a>
gbs
  • 3,529
  • 2
  • 20
  • 18
  • Brilliant but one serious issue- if I have an attribute other than 'title' and I do not want _if to apply to it... The _if still would. Still, the code-idea is good. – Phil Oct 01 '13 at 19:39
  • 5
    you can always add the other attribute using the ko standard 'attr' binding (which is not affected by the _if flag). example: data-bind="attrIf: {title: title, _if: flag}, attr: {otherAttr: val}" – gbs Oct 02 '13 at 10:40
  • i would recommend having some more logic around that removal on the bottom... this answer does not work if you want to conditionally override an attribute that already exists on the element. picture the following – MrTristan Feb 04 '16 at 20:13
8

Knockout's "attr" data binding does support this scenario just return null or undefined from your getDisabledState() function then it won't emit the attribute.

This answer was retrieved from Knockout attr binding with attributes like 'readonly' and 'disabled'

Community
  • 1
  • 1
zshift
  • 341
  • 5
  • 10
2

I wish I could have just replied to @gbs, but I can't. My solution would have been to have two of the same HTML element, one with the attribute, one without, and a knockout condition to add one of it according to the element. I also know about this custom biding, but which of the solution is more efficient?

  • And what do you do if you have 5 different attributes to the same element? Lot of fun in perspective... – Samuel Nov 10 '14 at 22:49