Knockoutjs.com - Grid editor example

http://knockoutjs.com/examples/gridEditor.html

by Doug Hill

HTML

<script src="http://knockoutjs.com/js/jquery.validate.js"></script>
<script src="http://knockoutjs.com/downloads/knockout-3.2.0.js"></script>
<div class='liveExample'> 
    
    <form action='/someServerSideHandler'>
        <p>You have asked for <span data-bind='text: gifts().length'>&nbsp;</span> gift(s)</p>
        <table data-bind='visible: gifts().length > 0'>
            <thead>
                <tr>
                    <th>Gift name</th>
                    <th>Price</th>
                    <th />
                </tr>
            </thead>
            <tbody data-bind='foreach: gifts'>
                <tr>
                    <td><input class='required' data-bind='value: name, uniqueName: true' /></td>
                    <td><input class='required number' data-bind='value: price, uniqueName: true' /></td>
                    <td><a href='#' data-bind='click: $root.removeGift'>Delete</a></td>
                </tr>
            </tbody>
        </table>
     
        <button data-bind='click: addGift'>Add Gift</button>
        <button data-bind='enable: gifts().length > 0' type='submit'>Submit</button>
    </form>
    
</div>

CSS

body { font-family: arial; font-size: 14px; }

.liveExample { padding: 1em; background-color: #EEEEDD; border: 1px solid #CCC; max-width: 655px; }
.liveExample input { font-family: Arial; }
.liveExample b { font-weight: bold; }
.liveExample p { margin-top: 0.9em; margin-bottom: 0.9em; }
.liveExample select[multiple] { width: 100%; height: 8em; }
.liveExample h2 { margin-top: 0.4em; font-weight: bold; font-size: 1.2em; }

.liveExample table, .liveExample td, .liveExample th { padding: 0.2em; border-width: 0; }
.liveExample td input { width: 13em; }
tr { vertical-align: top; }
.liveExample input.error { border: 1px solid red; background-color: #FDC; }
.liveExample label.error { display: block; color: Red; font-size: 0.8em; } 
.liveExample th { font-weight: bold; }

li { list-style-type: disc; margin-left: 20px; }

JavaScript

var GiftModel = function(gifts) {
    var self = this;
    self.gifts = ko.observableArray(gifts);
 
    self.addGift = function() {
        self.gifts.push({
            name: "",
            price: ""
        });
    };
 
    self.removeGift = function(gift) {
        self.gifts.remove(gift);
    };
 
    self.save = function(form) {
        alert("Could now transmit to server: " + ko.utils.stringifyJson(self.gifts));
        // To actually transmit to server as a regular form post, write this: ko.utils.postJson($("form")[0], self.gifts);
    };
};
 
var viewModel = new GiftModel([
    { name: "Tall Hat", price: "39.95"},
    { name: "Long Cloak", price: "120.00"}
]);
ko.applyBindings(viewModel);
 
// Activate jQuery Validation
$("form").validate({ submitHandler: viewModel.save });