Knockoutjs.com - Grid editor example

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

by Ben South

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
});