IsDirty and ko.mapping

by farina

HTML

<script src="https://github.com/downloads/SteveSanderson/knockout/knockout-2.0.0.debug.js"></script>
<script src="https://raw.github.com/SteveSanderson/knockout.mapping/master/build/output/knockout.mapping-latest.debug.js"></script>
<!--ko foreach: people-->    
<input data-bind="value: full()"></input> <span data-bind="text: full.isDirty()"></span><br />
<!--/ko-->


<button data-bind="click: loadInitialData">Load Initial Data</button>
<button data-bind="click: loadUpdatedData">Load Updated Data</button>

JavaScript

var data = [
    { id: 0, first: "Not", last: "Updated" },
    { id: 1, first: "Bob", last: "Smith" },
    { id: 2, first: "Jimmy", last: "Jones" },
    { id: 3, first: "Delete", last: "Me" }
];

var updatedData = [
    { id: 0, first: "Not", last: "Updated" },
    { id: 1, first: "Robert", last: "Smith" },
    { id: 2, first: "James", last: "Jones" },
    { id: 3, first: "New", last: "Guy" }
];

var Person = function(data) {
    this.id = data.id;
    this.first = ko.observable(data.first);
    this.last = ko.observable(data.last);
    this.full = ko.computed(function() {
        return this.first() + " " + this.last();
    }, this).extend({ dirty: false });        
};


var dataMappingOptions = {
    key: function(data) {
        return data.id;        
    },
    create: function(options) {
        return new Person(options.data);
    }        
};

var viewModel = {
    people: ko.mapping.fromJS([]),
    loadInitialData: function() {
        ko.mapping.fromJS(data, dataMappingOptions, viewModel.people);        
    },
    loadUpdatedData: function() {
        ko.mapping.fromJS(updatedData, dataMappingOptions, viewModel.people);  
    }        
};

ko.extenders.dirty = function(target, startDirty) {
  var cleanValue = ko.observable(ko.mapping.toJSON(target));
  var dirtyOverride = ko.observable(ko.utils.unwrapObservable(startDirty));
  
  target.isDirty = ko.computed(function(){
    return dirtyOverride() || ko.mapping.toJSON(target) !== cleanValue();
  });
  
  target.markClean = function(){
    cleanValue(ko.mapping.toJSON(target));
    dirtyOverride(false);
  };
  target.markDirty = function(){
    dirtyOverride(true);
  };
  
  return target;
};

ko.applyBindings(viewModel);