Knockout attr binding with attributes like 'readonly' and 'disabled'
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.
Related videos on Youtube
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, 2022Comments
-
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 over 11 yearsI don't understand, why you need to provide disabled if you don't disabled to even show?
-
Armchair Bronco over 11 yearsThe 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 over 11 yearsHow 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 over 11 yearsIf 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"
andundefined
. -
Armchair Bronco over 11 yearsOK. 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 about 10 yearsBe sure to pick the right one.
!observableProperty
does not work. The NOT!
is not picked up by the evaluator. -
mikus almost 10 years!observableProperty() works though :) much faster and often cleaner than a custom binding
-
Jacob Jedryszek over 9 yearsIf 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 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 about 8 yearsThanks for sharing the source, and including the code inline.
-
jpaugh about 6 yearsGreat 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 about 6 years@jpaugh, Sorry, I haven't used KO in several years. These days, I use the Aurelia framework.