Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to applyBindings and keep input values with Knockout JS?

I'm building a HTML/KnockoutJS application. My webserver returns a form with input fields with information. When I new up my model and do an ko.applyBindings, naturally the input values are overwritten by the model.

Is there a way to do an ko.applyBindings in which the model is automatically loaded with the data of the input fields?


Example: https://jsfiddle.net/KeesCBakker/p7ygq5y2/1/

HTML:

Title: <input data-bind="textInput: title" value="MyTitle" placeholder="Nothing here!" /><br/>
Text: <input data-bind="textInput: text" value="MyText" placeholder="Nothing here!" /><br/>
<button id="bind">Bind!</button>

JS:

ko.bindingHandlers.initFromInput = {
  init: function(element, valueAccessor) {
    valueAccessor()(element.value);
  }
};

function Model() {
  this.title = ko.observable();
  this.text = ko.observable();
}

document.getElementById('bind').onclick = function() {

  var model = new Model();
  ko.applyBindings(model);

};
like image 963
Kees C. Bakker Avatar asked Feb 09 '23 02:02

Kees C. Bakker


2 Answers

You could use a custom binding, that tells Knockout to use the input values as default, like this:

ko.bindingHandlers.initFromInput = {
    init: function(element, valueAccessor) {
        valueAccessor()(element.value);
    }
};

Here's a jsfiddle: http://jsfiddle.net/kv3zras3/3/

EDIT:

With the new binding, your data-binds should look something like this:

<input data-bind="initFromInput: title, value: title" value="MyTitle" placeholder="Nothing here!" />
<input data-bind="initFromInput: text, value:text" value="MyText" placeholder="Nothing here!" />

EDIT:

There's an abit nicer way of achieving this, if you make like binding look like this:

var origValueInput = ko.bindingHandlers.value.init;
ko.bindingHandlers.value.init = function(element, valueAccessor, allBindings) {
    if (allBindings.has('initValueFromInput')) {
        valueAccessor()(element.value);
    }
    origValueInput.apply(this, arguments);
};

You can write your data-binds like this:

<input value="MyTitle" data-bind="initValueFromInput, value: title"/>
<input value="MyText" data-bind="initValueFromInput, value: text"/>

Here's a fiddle: https://jsfiddle.net/yy51kok5/

like image 137
clean_coding Avatar answered Feb 10 '23 14:02

clean_coding


I've ended up improving the answer from clean_coding. Add the following anonymous method to a script after loading KnockoutJS. It will reroute both textInput and value handlers.

(function () {

    var z = ko.bindingHandlers.textInput.init;
    ko.bindingHandlers.textInput.init = function (element, valueAccessor, allBindings) {
        if (allBindings.has('initWithElementValue')) {
            valueAccessor()(element.value);
        }
        z.apply(this, arguments);
    };

    var y = ko.bindingHandlers.value.init;
    ko.bindingHandlers.value.init = function (element, valueAccessor, allBindings) {
        if (allBindings.has('initWithElementValue')) {
            valueAccessor()(element.value);
        }
        y.apply(this, arguments);
    };

}())

It can be used, by specifying it after the textInput or value declaration:

<input type="text" data-bind="textInput: title, initWithElementValue" />
like image 41
Kees C. Bakker Avatar answered Feb 10 '23 14:02

Kees C. Bakker