Non observable form values

by origineil

HTML

<!-- Template: View/edit employees --> 
<script type="text/html" id="viewing-template">
  <p><b>Name</b>
      <span style="float: right" ><span data-bind="text: firstName().value"></span> <span data-bind="text: lastName().value"></span></span>
  </p>
  <p><b>Fund name</b>
  <span style="float: right"><span data-bind="text: fundName().value"></span>
  </p>
</script>

<script type="text/html" id="editing-template">
  First name: <br />
    <input data-bind="value: firstName().modifiedValue" type="text"/>  <span data-bind="text: firstName().value"></span><br />
  Last name: <br />
  <input data-bind="value: lastName().modifiedValue" type="text"/>  <span data-bind="text: lastName().value"></span><br />
  Fund name: <br />
  <input data-bind="value: fundName().modifiedValue" type="text"/>  <span data-bind="text: fundName().value"></span><br />
</script> 

<!-- Main -->
<article class="content">
 <h1>Employee details</h1>

 <div class="employees" data-bind="foreach: { data: employees }"> 

  <!-- Individual -->
  <div class="employee-summary">
   <h3>Employee details</h3>
   <fieldset>

<!-- ko if: editable -->
    <div class="employee" data-bind="template: {name: 'editing-template',  data: $data }"> </div>
<!-- /ko --> 

<!-- ko ifnot: editable -->
    <div class="employee" data-bind="template: {name: 'viewing-template', data: $data }"> </div>
<!-- /ko -->
    <br />
    <div style="float: right; display: inline;">
     <button data-bind='click: removeEmployee'>Delete</button>
        <span data-bind="if: editable()"><button data-bind='click: cancelUpdate'>Cancel</button></span>
     <button data-bind='click: editEmployee'>
      <span data-bind="ifnot: editable()">Edit</span>
      <span data-bind="if: editable()">Save</span>
     </button>
    </div>
    <br />
    <br class="clear" />
   </fieldset>
  </div>
<!-- End individual -->
  <br />

<!-- End employees -->
 </div>
 <div style="clear: left">
  <div style="float: right">
   <button data-bind='click:...

CSS

body {
    font-family: Arial, Helvetica, sans-serif;
}
}
.content {
    width: 60em;
    margin: 0 auto;
}
fieldset {
    padding: 1em;
    border: solid 1px #ccc;
}
.input-row h3, .employee h3, h3 {
    padding: .25em .5em;
    background-color: #eee;
    margin: 0;
}
.input-row ul, ul.qtr li {
    list-style: none;
}
.employees {
    padding: 0;
    list-style: none;
}
ul.qtr, ul.qtr li {
    margin: 0;
    padding: 0;
}
.clear {
    clear: both;
}
button {
    display: inline-block;
    outline: none;
    cursor: pointer;
    text-align: center;
    text-decoration: none;
    font: 14px/100% Arial, Helvetica, sans-serif;
    padding: .5em 1.3em .5em;
    -webkit-border-radius: .5em;
    -moz-border-radius: .5em;
    border-radius: .5em;
    border: solid 1px #999;
    background: #eee;
}
button:hover {
    text-decoration: none;
    background: #ccc;
}
button:active {
    position: relative;
    /* top: 1px;*/
    color: #000;
}

JavaScript

function ModifiedObservable() {
    this.createObservable = function(){
        var observable = ko.observable({value: "", modifiedValue: ""});
        observable.revert = function(){this.modifiedValue = this.value; }.bind(observable())
        observable.save = function(){ this.value = this.modifiedValue;  }.bind(observable())
        return observable
    };
    
    this.saveAccessor = function(){
        return "save";
    }
    
    this.revertAccessor = function(){
        return "revert";
    }
}

function Employee() {

    var self = this;
    
    this.obsWrapper = new ModifiedObservable();
    
    this.firstName = this.obsWrapper.createObservable();
    this.lastName = this.obsWrapper.createObservable();
    this.fundName = this.obsWrapper.createObservable();
 
    //Toggle editability
    this.editable = ko.observable(true);
 
    // Employee summary of details
    this.removeEmployee = function (employee) {
        vm.removeEmployee(this);
    };

    this.cancelUpdate = function () {   
    this.editable(!this.editable());
    this._handleProperties(this.obsWrapper.revertAccessor());
    };

    this.editEmployee = function (employee) {
        var isSaving = this.editable();
        this.editable(!this.editable());

        if(isSaving)
        {
          this._handleProperties(this.obsWrapper.saveAccessor());
        }
         
    };
 
    this._handleProperties = function(functionName)
    {
       for(var i = 0; i < this._getProperties().length; i++)
       {
          var propertyName = this._getProperties()[i];
          var observable = this[propertyName];
          observable[functionName]();
          observable.valueHasMutated();
       }
    }
        
    this._getProperties = function(){
    return ["firstName", "lastName", "fundName"]
    }
}


function EmployeesViewModel() {

    var self = this;

    self.employees = ko.observableArray([]);

    self.removeEmployee = function (employee) {
        self.employees.remove(employee);
 ...