Search code examples
knockout.jsknockout-validation

How do I conditionally bind to "valueUpdate" in knockout.js?


I am currently using knockout.js and the knockout.validation.js plugin which works quite nicely in most situations. What I have been struggling with is getting the validation to fire for the first time when an input blurs and then every time after that to fire on a per keystroke basis. I really feel like the following code should work for this.

<input type="text" class="form-control"
       data-bind="value: Name, 
           valueUpdate: Name.isModified() ? 'afterkeydown' : '',
           style: { background: Name.isModified() ? 'red' : 'green'}" 
/>

For some reason the valueUpdate doesn't change to afterkeydown when isModified() changes, but the background color does properly change as I would expect. (That line of code is only there to help with debugging).

What am I doing wrong that is keeping the valueUpdate method from properly updating when the isModified observable changes?

Edit:

I think I may have done a poor job of asking this question. What I would like to know is why doesn't this code:

<input type="text" class="form-control"
       data-bind="value: Name, 
           valueUpdate: Name.isModified() ? 'afterkeydown' : ''"
/>

behave like this code:

<!-- ko if: Name.isModified() -->
    <input type="text" 
           class="form-control" 
           data-bind="value: Name, valueUpdate: 'afterkeydown'" />
<!-- /ko -->
<!-- ko if: !Name.isModified() -->
    <input type="text" class="form-control" data-bind="value: Name" />
<!-- /ko -->

It seems to me like you can't conditionally bind to the "valueUpdate" property and I am unable to confirm this in any of the knockout documentation. In the first case, the valueUpdate doesn't change to 'afterkeydown' when Name.isModified updates. What is going on?


Solution

  • This is the definition of Knockout's value binding. At lines 14+ you will start to see the initial event handlers attached to the elements. 'change' is attached, along with any other defined handler, like valueUpdate requested handlers.

    Unfortunately (or not) as you see they are fetched and executed once during the inputs initialization, so when you try to change the value of the binding it has no effect, nothing in Knockout is monitoring it.

    Your 2nd example is the way to go for when you want to dynamically change that binding parameter, BUT in your case i think you are not doing it correctly.

    Knockout-validation validators come with an option to define an onlyIf callback, to allow you to run/stop validations. What you would like to do is to have an observable been evaluated in that onlyIf callback, and to set that observable in your desired cases to true ( on input blur or anything else) onlyIf docs