ko-add row

How do you add a row to an editable table in Knockout.js?

by supercool

HTML

<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.3.5/knockout.mapping.js"></script>
<div id="ko">
    <table>
        <thead>
            <tr>
                <th>Col 1</th>
                <th>Col 2</th>
                <th>Col 3</th>
                <th>Total</th>
            </tr>
        </thead>
        <tbody data-bind='foreach:List'>
            <tr>
                <!-- ko foreach:Entries-->
                <td>
                    <input size="3" type="text" data-bind="value:Hours, valueUpdate:'afterkeydown'" />
                </td>
                <!-- /ko -->
                <td> <span data-bind="text:Total"></span> 
                </td>
            </tr>
        </tbody>
    </table>
    <button type="button" value="click" data-bind="click: addRow">addRow</button>
    
<h4>jsonList</h4>

<span data-bind="text: ko.toJSON($data,null,2)"></span>

</div>

JavaScript

var data = {
    "Lines": [{
        "Entries": [{
            "Hours": 5.5
        }, {
            "Hours": 2.50
        }, {
            "Hours": 3.75
        }]
    }, {
        "Entries": [{
            "Hours": 5.1
        }, {
            "Hours": 2.00
        }, {
            "Hours": 4.75
        }]
    }, {
        "Entries": [{
            "Hours": 1.2
        }, {
            "Hours": 3.00
        }, {
            "Hours": 2.12
        }]
    }]
}

    function model(data) {
        var self = this;
        self.Entries = ko.observableArray();
        self.Total = ko.computed(function () {
            var sum = 0;
            ko.utils.arrayForEach(self.Entries(), function (entry) {
                var value = parseFloat(entry.Hours(), 10);
                if (!isNaN(value)) {
                    sum += value;
                }
            });
            return sum;
        });
        ko.mapping.fromJS(data, {}, self);
    }

var mapping = {
    create: function (options) {
        return new model(options.data);
    }
}

var data1 = {
    "Entries": [{
        "Hours": 1
    }, {
        "Hours": 2
    }, {
        "Hours": 3
    }]
};


function ViewModel() {
    var self = this
    self.List = ko.observableArray([])
    self.LoadData = function (data) {
        ko.mapping.fromJS(data.Lines, mapping, self.List)
        console.log(self.List())
    }
    self.LoadData(data);
    self.addRow = function () {
        self.List.push(ko.mapping.fromJS(data1,mapping));
    }
}


ko.applyBindings(new ViewModel(), document.getElementById('ko'))