Guard your model++

http://www.knockmeout.net/2011/03/guard-your-model-accept-or-cancel-edits.html PAEz - added some stuff to check if an items new and delete it on a cancel.

HTML

<script src="http://rniemeyer.github.com/KnockMeOut/Scripts/jquery.tmpl.js"></script>
<script src="http://rniemeyer.github.com/KnockMeOut/Scripts/knockout-latest.debug.js"></script>
<table>
  <tr>
    <th>Name</th>
    <th>Quantity</th>
    <th></th>
    <th></th>
  </tr>
  <tbody data-bind="template: { name: templateToUse, foreach: items}"></tbody>
</table>

<script id="itemTmpl" type="text/html">
  <tr>
    <td data-bind="text: name"></td>
    <td data-bind="text: quantity"></td>
    <td class="buttons">
      <button data-bind="click: function() { viewModel.editItem($data); }, visible: !viewModel.isEditing()">Edit</button>
      <button data-bind="click: function() { viewModel.deleteItem($data); }, visible: !viewModel.isEditing()">Delete</button>
    </td>
  </tr>
</script>

<button data-bind="click: newItem, enable: !viewModel.isEditing()">New Item</button>

<button onclick="Tester()">Tester</button>
<button onclick="viewModel.saveItems()">Save</button>
<button onclick="viewModel.loadItems()">Load</button>
<button onclick="viewModel.clearSavedItems()">Clear Save</button>
<script id="editTmpl" type="text/html">
  <tr>
    <td>
      <input data-bind="value: name" />
    </td>
    <td>
      <input data-bind="value: quantity" />
    </td>
    <td class="editButtons">
      <button data-bind="click: function() { viewModel.acceptItemEdit() }, visible:viewModel.isEditing()">Accept</button>
      <button data-bind="click: function() { viewModel.cancelItemEdit() }, visible:viewModel.isEditing()">Cancel</button>
      <div data-bind="visible:isNew()"><br />Its new</div>
    </td>
  </tr>
</script>

CSS

input {
  width: 75px;
}

table,
th,
td {
  border-style: none;
  margin: 0px;
  padding: 0px;
}

td {
  width: 80px;
  height: 26px !important;
}

th {
  color: #666;
  font-size: .8em;
}

.buttons {
  width: 150px;
}

.editButtons {
  width: 150px;
}

.buttons button {
  visibility: hidden;
  opacity: 0;
  -webkit-transition: opacity 0.2s ease-in-out;
}

tr:hover .buttons button {
  visibility: visible;
  opacity: 1;
}

.editButtons button {
  opacity: 1;
  -webkit-transition: opacity 0.2s ease-in-out;
}

.button {
  visibility: visible;
  opacity: 1;
  -webkit-transition: opacity 0.2s ease-in-out;
}

JavaScript

//wrapper for an observable that protects value until committed
ko.protectedObservable = function(initialValue) {
  //private variables
  var _temp = initialValue;
  var _actual = ko.observable(initialValue);

  var result = ko.dependentObservable({
    read: function() {
      return _actual();
    },
    write: function(newValue) {
      _temp = newValue;
    }
  });

  //commit the temporary value to our observable, if it is different
  result.commit = function() {
    if (_temp !== _actual()) {
      _actual(_temp);
    }
  };

  //notify subscribers to update their value with the original
  result.reset = function() {
    _actual.valueHasMutated();
    _temp = _actual();
  };

  return result;
};

//construct an Item

function Item(item) {

  if ("new" in item) {
    this.new = true; //ko.observable(item.isNew);
  };
  if ("name" in item) {
    this.name = ko.protectedObservable(item.name);
  } else {
    this.name = ko.protectedObservable("");
  };
  if ("quantity" in item) {
    this.quantity = ko.protectedObservable(item.quantity);
  } else {
    this.quantity = ko.protectedObservable(0);
  };
  this.commit = function() {
    this.name.commit();
    this.quantity.commit();
  };
  this.reset = function() {
    this.name.reset();
    this.quantity.reset();
  };
  //use this to set the modals header by
  this.isNew = function() {
    if ("new" in this) return true;
    return false;
  };
  this.notNew = function() {
    delete(this.new);
  }
}

var viewModel = {
  items: ko.observableArray(),

  isEditing: ko.observable(),

  selectedItem: ko.observable(),

  addItem: function(item) {
    var newItem = new Item(item);
    this.items.push(newItem);
  },
  addItems: function(items) {
    for (i = 0; i < items.length; i++) {
      this.addItem(items[i]);
    }
  },
  newItem: function() {
    var newItem = new Item({
      new: true
    });
    this.items.push(newItem);
    this.selectedItem(newItem);
    this.isEditing(true);
  },
  deleteItem:...