scaryman
scaryman

Reputation: 1900

Custom binding with viewmodel and controlsDescendantBindings not updating

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

Answers (2)

tabalin
tabalin

Reputation: 2313

I'll try to explain why below code worked and above code doesn't.

  1. 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.

  1. 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

tabalin
tabalin

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

Related Questions