Okky
Okky

Reputation: 10466

Knockout JS: Binding Dynamic Rows

I'm having some trouble in binding dynamically created dom elements

Code:

var i=0;

$.each(data.info, function(index, element) {                        
    $("#div1").append("<tr><td>" + element.Name + "</td><td>"+ element.Major +"</td><td>" + element.Sex +"</td><td>" + "<input data-bind='value: eng"+i+"' ></td><td>" + "<input data-bind='value: jap"+i+"' ></td><td>" +  "<input data-bind='value: cal"+i+"' ></td><td>" + "<input data-bind='value: geo"+i+"' ></td><td>" + "<strong data-bind='text: total'></td>" )
i++;
});

This creates row with input data-bind values eng0, eng1, jap0, jap1, etc.

I want to bind these as observables

Code

function AppViewModel() {
    this.eng = ko.observable(element.English);
    this.jap = ko.observable(element.Japanese);
    this.cal = ko.observable(element.Calculus);
    this.geo = ko.observable(element.Geometry);

    this.total = ko.computed(function() {
    var tot=parseFloat(this.eng()) + parseFloat(this.jap()) + parseFloat(this.cal()) + parseFloat(this.geo());
    return (tot);    
    }, this);

}

    ko.applyBindings(new AppViewModel());

This code is also inside $.each(data.info, function(index, element){}

I want some thing like

Var i=0;
$.each(data.info, function(index, element) {

function AppViewModel() {
        this.eng+i = ko.observable(element.English);
        this.jap+i = ko.observable(element.Japanese);
        this.cal+i = ko.observable(element.Calculus);
        this.geo+i = ko.observable(element.Geometry);

        this.total+i = ko.computed(function() {
        var tot=parseFloat(this.eng()) + parseFloat(this.jap()) + parseFloat(this.cal()) + parseFloat(this.geo());
        return (tot);    
        }, this);

    }
i++;
}

That get me result this.eng0 = ko.observable()

Note: the data is obtained from a JSON object. I have only included the iteration path

Upvotes: 2

Views: 940

Answers (1)

Jeroen
Jeroen

Reputation: 63729

May I suggest that using a foreach binding may be better than using jQuery's each and generating the HTML yourself? I'd suggest changing your view model to something like this:

function AppViewModel() {
   this.items = ko.observableArray();
}

function ItemViewModel(element) {
    this.eng = ko.observable(element.English);
    this.jap = ko.observable(element.Japanese);
    this.cal = ko.observable(element.Calculus);
    this.geo = ko.observable(element.Geometry);

    this.name = ko.observable(element.name);
    this.major = ko.observable(element.major);
    this.sex = ko.observable(element.sex);

    this.total = ko.computed(function () {
        var tot = parseFloat(this.eng()) + parseFloat(this.jap()) + parseFloat(this.cal()) + parseFloat(this.geo());
        return (tot);
    }, this);

};

Here, the AppViewModel is a container for the list of elements, and each element is its own ItemViewModel, with the properties you seem to have.

The html to bind this would be something like this:

<table>
    <tbody data-bind="foreach: items">
    <tr>
        <td data-bind="text: name"></td>
        <td data-bind="text: major"></td>
        <td data-bind="text: sex"></td>
        <td><input data-bind='value: eng' /></td>
        <td><input data-bind='value: jap' /></td>
        <td><input data-bind='value: cal' /></td>
        <td><input data-bind='value: geo' /></td>
        <td><strong data-bind='text: total' /></td>
    </tr>
    </tbody>
</table>

When you get the JSON from your server you can use Knockout's built-in JSON stuff, the mapping plugin, or parse them yourself. I created an example using the latter option in this jsfiddle.

Upvotes: 5

Related Questions