Search code examples
eventsknockout.jsdefault

Knockout - Disabling the default behavior of updating model when using binding value with form element


Knockout has the default behavior of updating the associated model if you change your focus (e.g. by clicking outside the input control) after editing the value inside an input control, populated by a binding of type Value.

Here is the link to the official documentation page explanation, section Parameters:

http://knockoutjs.com/documentation/value-binding.html

Do you know a way to disable this default behavior ?

The reason behind this : Im using Models that can tell if their last update requires persistent backup by comparing the previous value to the new one. I would like to listen to the key up event on my form inputs but if I do that, knockout triggers twice event (the default one + the key up) to update the Model and the second one is basically telling my Model to replace the value by the same value because it is already updated, which it translates to "there is no need to do persistent backup since the value didnt change".

I would gladly appreciate any help or suggestion, since Im stuck and can't find a way around :)

EDIT Couldnt reproduce the error with bare backbone code. It seems as "super cool" said that valueUpdate should override the default Blur event that triggers when you use form controls with binding Value. It may be a bug introduced by the library Knockback that I use to create the ViewModel.

Despite all this, just replacing the binding Value by the binding textInput did the trick. Thank you all.


Solution

  • Don't listen to the event, subscribe to updates, which won't fire unless the value is changed. Using the textInput binding will register every change to the value, even those done using menu items like cut and paste, when they happen.

    Equivalently, you can use the value binding along with valueUpdate: 'input'

    vm = {
      myvar: ko.observable(),
      updates: ko.observableArray()
    };
    
    vm.myvar.subscribe(function(newValue) {
      vm.updates.push(newValue);
    });
    ko.applyBindings(vm);
    <script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
    <input data-bind="textInput: myvar" />
    <div data-bind="foreach: updates">
      <div data-bind="text: $data"></div>
    </div>