Initializing your knockout bindings from HTML with the initValue binding

by joeyespo

HTML

<!-- Note that you can use the model before the initializing fields below -->
<h1><span data-bind="text: firstName"></span> <span data-bind="text: lastName"></span></h1>

<!-- Example: valueWithInit -->
<p>
    First name:
    <input type="text" data-bind="valueWithInit: firstName" value="Joe" />
</p>

<!-- Example: separate initValue and value bindings -->
<p>
    Last name:
    <input type="text" data-bind="initValue: lastName, value: lastName" value="Smith" />
</p>

<!-- Example: checkedWithInit -->
<p>
    Employed:
    <input type="checkbox" data-bind="checkedWithInit: isEmployed" checked />
</p>

<!-- Here's the entire model in JSON form -->
<hr />
<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>

CSS

input {
    margin: 2px;
}

JavaScript

// --- View model ---

var viewModel = {
    firstName: ko.observable('This will be overwritten'),
    lastName: ko.observable(),
    isEmployed: ko.observable(),
};


// --- Knockout binding handlers ---

ko.bindingHandlers.initValue = {
    init: function(element, valueAccessor) {
        var value = valueAccessor();
        if (!ko.isWriteableObservable(value)) {
            throw new Error('Knockout "initValue" binding expects an observable.');
        }
        value(element.value);
    }
};

ko.bindingHandlers.initChecked = {
    init: function(element, valueAccessor) {
        var value = valueAccessor();
        if (!ko.isWriteableObservable(value)) {
            throw new Error('Knockout "initChecked" binding expects an observable.');
        }
        value(element.checked);
    }
};

ko.bindingHandlers.valueWithInit = {
    init: function(element, valueAccessor, allBindings, data, context) {
        ko.applyBindingsToNode(element, { initValue: valueAccessor() }, context);
        ko.applyBindingsToNode(element, { value: valueAccessor() }, context);
    }
};

ko.bindingHandlers.checkedWithInit = {
    init: function(element, valueAccessor, allBindings, data, context) {
        ko.applyBindingsToNode(element, { initChecked: valueAccessor() }, context);
        ko.applyBindingsToNode(element, { checked: valueAccessor() }, context);
    }
};


// --- Bind the document ---

ko.applyBindings(viewModel);