Question

What would be the idiomatic way to populate a KnockoutJS-backed form with data that is fetched asynchronously from a server using HTTP GET? The issue I'm running into is that if I don't create an empty dummy instance of the domain model (see code below), Knockout breaks because it tries to call domainModel().name and domainModel().description for the form fields before the $.getJSON call is finished.

What is the common way of handling this situation? Should I do the $.getJSON first and call ko.applyBindings(new ViewModel(domainModelData)); in the success callback or is there some other way?

HTML & inline Javascript:

<form data-bind="submit: update">
    <input id="name" data-bind="value: domainModel().name"/>
    <input id="description" data-bind="value: domainModel().description"/>
    <button type="submit"/>     
</form>


<script type="text/javascript">
    $(document).ready(function () {
        ko.applyBindings(new ViewModel());
    });
</script>

The Knockout view model:

function DomainModel(data) {
    var self = this;
    self.id = ko.observable(data.id);
    self.name = ko.observable(data.name);
    self.description = ko.observable(data.description);
}

function ViewModel() {
    var self = this;

    // This feels somehow dirty
    self.domainModel = ko.observable(new DomainModel({id: null, name: "", description: ""}));

    self.update = function() {
        ...
    };

    $.getJSON("domainModel/<id>", function(domainModelData) {
        self.domainModel(new DomainModel(domainModelData));
    });
}
Was it helpful?

Solution

You should use the with binding or foreach binding to ensure the object exists before the bindings attempt to resolve -

<form data-bind="submit: update, with: domainModel">
    <input id="name" data-bind="value: name"/>
    <input id="description" data-bind="value: description"/>
    <button type="submit"/>     
</form>

Basically, until domainModel has a value name and description will not be resolved. Another approach is to use a $data. prefix to say 'if there is no data, wait until there is'

<form data-bind="submit: update">
    <input id="name" data-bind="value: $data.domainModel().name"/>
    <input id="name" data-bind="value: $data.domainModel().description"/>
    <button type="submit"/>     
</form>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top