Lemuel Nitor
Lemuel Nitor

Reputation: 333

Knockout with multiple valueUpdates

I'm a newbie when it comes to using knockout, I really want to maximize it's usage in the web that I am developing. But I am having concerns when it comes to the browsers capability to listen to multiple user events. I believe that knockout implements a property called valueupdate. So far, I have only used 'afterkeydown' and 'blur'. But I need my browser to listen to multiple events at the same time. Below are the user events that my browser should listen to:

  1. On page load, I want my input fields to start validating on page load.
  2. On blur, I want my input fields to validate after it losts focus.
  3. After key down, I also want my fields to re-validate them selves after the user presses a key.
  4. On submit, though my fields are not wrapped in a form, I still want to validate my fields, after the user clicks the "Save" button.

I'm thinking of something like this:

<input data-bind="value:someObservable, valueUpdate:'blur' + 'afterKeyDown' + 'onLoad' + 'onClickOfSaveButton'" />

--> Something like that, though I know this will cause a syntax error, but I hope you get my point.

I know, this question is kinda confusing, but if you want more details, please don't hesitate to specify it on your comment. I really need help here. Thanks.

Upvotes: 10

Views: 14137

Answers (3)

Simon_Weaver
Simon_Weaver

Reputation: 145950

You should check out textInput binding. This is the best way to correctly listen to all kinds of events that can affect the value of a text input field.

<input data-bind="textInput: userName" />

Unlike the value binding, textInput provides instant updates from the DOM for all types of user input, including autocomplete, drag-and-drop, and clipboard events.

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

Upvotes: 3

matrix10657
matrix10657

Reputation: 513

Always happy to see a 'newbie' decide to make the switch to KnockoutJS. Anything that can help rid the world of verbose, ad hoc data-binding solutions is a wonderful thing.

To answer your question regarding how to key off multiple events to update your data-binding value, you would write:

<input data-bind="value:someObservable, valueUpdate: ['blur', 'afterKeyDown', 'onLoad']"/>

In my case, I was using a bootstrap typeahead to select a value, but the data-binding was not being refreshed after the user made a selection from the dropdown suggestion box. After looking at the source, I found this little hidden gem that was not mentioned on the KO docs.

I cringe telling anyone to "go read the source", but if you're dealing with a fringe case that isn't covered in the docs, don't be scared to! I've uncovered many undocumented features by doing so

source: https://github.com/knockout/knockout/blob/master/src/binding/defaultBindings/value.js

ko.bindingHandlers['value'] = {
    'init': function (element, valueAccessor, allBindingsAccessor) {
        // Always catch "change" event; possibly other events too if asked
        var eventsToCatch = ["change"];
        var requestedEventsToCatch = allBindingsAccessor()["valueUpdate"];
        var propertyChangedFired = false;
        if (requestedEventsToCatch) {
            // Allow both individual event names, and arrays of event names
            if (typeof requestedEventsToCatch == "string")       
                requestedEventsToCatch = [requestedEventsToCatch];
            ko.utils.arrayPushAll(eventsToCatch, requestedEventsToCatch);
            eventsToCatch = ko.utils.arrayGetDistinctValues(eventsToCatch);
        }
    .... truncated ....

Depending on your familiarity with writing bindings, it may be fairly apparent that the valueUpdate binding handles an array of events. Here they're getting the supplemental binding "valueUpdate" and storing it in var requestedEventsToCatch . The next comment marks the logic to handle an array of events to update the value on -- indeed they cast even a single event such as "afterKeyDown" to ["afterKeyDown"]

Hope this helps!

Upvotes: 23

Damien
Damien

Reputation: 8987

I made a fiddle that demonstrates how validate fields value on :

  • load by calling explictly isValid
  • when the value changed by the 'valueUpdate :afterKeyDown' parameter
  • right before sending data by calling explictly isValid in the submit method.

View :

<div>
    <input type="text" data-bind="value: name, valueUpdate : 'afterkeydown'" />
    <br/>
    <button data-bind="click: submit">Submit</button> 
</div>

JS :

ko.validation.configure({
    decorateElement: true, // add 'validationElement' class on invalid element
});

var VM = function () {
    var self = this;
    self.name = ko.observable("0").extend({
        minLength: 3
    });
    self.isValid = function () {
        self.name.valueHasMutated();
        return self.name.isValid();
    }

    self.submit = function () {
        if (self.isValid()) {
            // server call
        }
    };
};

var vm = new VM();
ko.applyBindings(vm);
vm.isValid();

See fiddle

I used the knockout.validation to perform validation tests.

Upvotes: 4

Related Questions