Knockout attr binding with attributes like 'readonly' and 'disabled'

24,636

Solution 1

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.

Demo Fiddle.

Solution 2

You can also create a binding for readonly like this:

ko.bindingHandlers['readonly'] = {
'update': function (element, valueAccessor) {
    var value = ko.utils.unwrapObservable(valueAccessor());
    if (!value && element.readOnly)
        element.readOnly = false;
    else if (value && !element.readOnly)
        element.readOnly = true;
}
};

Source: https://github.com/knockout/knockout/issues/1100

Solution 3

Knockout has an enable binding as well as a disable binding.

I'm not sure if these were available when the question was asked, but anyone referring back to this issue should be aware.

Share:
24,636

Related videos on Youtube

Armchair Bronco
Author by

Armchair Bronco

CEO & Co-Founder of http://ipredikt.com, a predictions-based social media entertainment built around user-generated predictions. "Vote early, vote often" at http://ipredikt.com. See "Tomorrow's News, Today"

Updated on July 12, 2022

Comments

  • Armchair Bronco
    Armchair Bronco almost 2 years

    What's the suggested "best practice" way to use Knockout's "attr" data binding with standalone attributes like "readonly" and "disabled"?

    These attributes are special in that they are generally enabled by setting the attribute value to the attribute name (although many browsers work fine if you simply include the attribute names without any values in the HTML):

    <input type="text" readonly="readonly" disabled="disabled" value="foo" />
    

    However, if you don't want these attributes to be applied, the general practice is to simply omit them altogether from the HTML (as opposed to doing something like readonly="false"):

    <input type="text" value="foo" />
    

    Knockout's "attr" data binding doesn't support this scenario. As soon as I provide an attribute name, I need to provide a value as well:

    <input type="text" data-bind="attr: { 'disabled': getDisabledState() }" />
    

    Is there a cross-browser way turn off 'disabled' or 'readonly'? Or is there a trick with a custom binding that I can use to not render anything if I don't want the item disabled or made read-only?

    • jjperezaguinaga
      jjperezaguinaga over 11 years
      I don't understand, why you need to provide disabled if you don't disabled to even show?
    • Armchair Bronco
      Armchair Bronco over 11 years
      The example I gave is designed to simply demonstrate the problem. The issue is this: some attributes in HTML are standalone attributes - they don't really require a value. And if you don't want these attributes to affect the HTML, then you simply omit them. But Knockout's "attr" data-binding mechanism doesn't support this scenario.
  • Armchair Bronco
    Armchair Bronco over 11 years
    How can I verify that the attribute hasn't been emitted using Firebug or a similar tool? When I try to view the "live" HTML from the demo Fiddle above, I'm still seeing the Knockout data-binding code, not the live, rendered <INPUT> tags. (However, I'll admit that it never occurred to me to do this; in my getDisabledState() function, I was always returning either "disabled" or the empty string "").
  • nemesv
    nemesv over 11 years
    If my fiddle working with your browser then it is working. I don't use Firebug. In the Chrome dev tools it is clear that it adds and removes the attribute if you return "disabled" and undefined.
  • Armchair Bronco
    Armchair Bronco over 11 years
    OK. I have verified this using Chrome. Thanks for the quick response and the demo Fiddle. It's a simple and elegant solution that never occurred to me. I typically initialize my return values to the expected data type (which for 'disabled' or 'readonly' is a string). I'll just initialize to 'undefined' and I should be good to go. Thanks!
  • yairr
    yairr about 10 years
    Be sure to pick the right one. !observableProperty does not work. The NOT ! is not picked up by the evaluator.
  • mikus
    mikus almost 10 years
    !observableProperty() works though :) much faster and often cleaner than a custom binding
  • Jacob Jedryszek
    Jacob Jedryszek over 9 years
    If you getDisabledState() function return true/false, you can use ternary operator inline, without modifying your function: <input type="text" data-bind="attr: { 'disabled': getDisabledState() ? 'disabled' : null }" /> I will have the same effect as returning string or null.
  • John Zabroski
    John Zabroski about 8 years
    @P.Brian.Mackey That is a common Knockout beginner mistake. When you add an operator like ! in front of an observableProperty, you need to explicitly call it by adding () at the end of the propertyName. This tells Knockout to lift the whole expression to a synthetic computed. If you use Chrome Debugger and type in a bogus observableProperty that doesn't exist, it will generate an error with a VM:SomeLineNumber in the Console. Click the VM:SomeLineNumber and you will see what Knockout generated.
  • John Zabroski
    John Zabroski about 8 years
    Thanks for sharing the source, and including the code inline.
  • jpaugh
    jpaugh about 6 years
    Great post! Could you also include a demo of how to use it? I'm sure I could figure it out, but I've never made a custom binding before, and it would be useful to others as well.
  • Greg Gum
    Greg Gum about 6 years
    @jpaugh, Sorry, I haven't used KO in several years. These days, I use the Aurelia framework.