Reputation: 1900
I have a custom binding, ko.bindingHandlers.editBinding
that does a lot of magic stuff. One of them is a readonly parameter that controls whether or not it will give the option to edit the referenced observable.
<div data-bind="editBinding: { type: 'text', prop: OrderContactName, readonly: CurrentOrderSystemStatusID() != 1 }"></div>
The readonly binding is relatively new, and can change during a session via external events. So, when it changes, all currently editing widgets need to discard all changes and close AND hide the ability to edit.
My custom vm has a computed for the readonly that doesn't update when it's passed in dependancy does, and I can't figure out why.
self.readOnly = ko.computed(function() {
return ko.utils.unwrapObservable(valueAccessor().readonly) || false;
});
Also interesting:
self.toggleFunc = function() {
var isEditing, otherEditingVM, _ref;
//this works
//original coffeescript
//#if valueAccessor()?.readonly and ko.utils.unwrapObservable valueAccessor().readonly is true then return
//if (((_ref = valueAccessor()) != null ? _ref.readonly : void 0) && ko.utils.unwrapObservable(valueAccessor().readonly === true)) {
//this doesn't
if (self.readOnly()) {
return;
}
base markup
<div data-bind="editBinding: { type: 'text', prop: OrderContactName, readonly: CurrentOrderSystemStatusID() != 1 }"></div>
when I move the readonly into the viewmodel it works! Why though? Doesn't knockout evaluate inline expressions to computeds anyways?
self.ShouldBeReadOnly = ko.computed(function() { return self.CurrentOrderSystemStatusID() === 0;})
<div data-bind="editBinding: { type: 'text', prop: OrderContactName, readonly: ShouldBeReadOnly }"></div>
I pulled a bunch of stuff out and made a nice jsfiddle for your viewing pleasure - http://jsfiddle.net/scaryman/QDgde/3/
EDIT
Knockout just doesn't work the way I thought it did. If I move the logic into a computed in the viewModel, it works (see the update), AND if I wrap the inline logic with a ko.computed, it works as well.
<div data-bind="editBinding: { type: 'text', prop: OrderContactName, readonly: ko.computed(function() {return CurrentOrderSystemStatusID() != 1;}) }"></div>
That still doesn't explain to me why the below code worked in the event handler
//#if valueAccessor()?.readonly and ko.utils.unwrapObservable valueAccessor().readonly is true then return
if (((_ref = valueAccessor()) != null ? _ref.readonly : void 0) && ko.utils.unwrapObservable(valueAccessor().readonly === true)) {
Upvotes: 0
Views: 165
Reputation: 2313
I'll try to explain why below code worked and above code doesn't.
Working
//#if valueAccessor()?.readonly and ko.utils.unwrapObservable valueAccessor().readonly is true then return if (((_ref = valueAccessor()) != null ? _ref.readonly : void 0) && ko.utils.unwrapObservable(valueAccessor().readonly === true)) {
Here your viewmodel has access to value through valueAccessor, which always gives actual model state. If you change the 'readonly', accessor gives its new value.
Not working
if (self.readOnly()) {
Here you access your viewmodel computed 'readOnly'. But the value of this computed is not being changed, when you change the value of 'readonly'. You always get first value. Because this computed doesn't have any computeds or observables that influence its value. Put alert('hey') in your readOnly computed, and you'll see that no notification happen when you change the 'readonly'.
Upvotes: 1
Reputation: 2313
You are right, knockout doesn't evaluate inline expressions to computeds, so you have to wrap the expression like CurrentOrderSystemStatusID() === 0 to computed, for example
readonly: ko.computed(function() { return CurrentOrderSystemStatusID() === 0; })
Upvotes: 1