Creating a smart, dirty flag
http://www.knockmeout.net/2011/05/creating-smart-dirty-flag-in-knockoutjs.html
by andrew rowe
HTML
<script src="http://knockoutjs.com/downloads/knockout-3.2.0.js"></script>
<ul data-bind="template: { name: 'itemsTmpl', foreach: items }"></ul>
<script id="itemsTmpl" type="text/html">
<li data-bind="css: { dirty: dirtyFlag.isDirty }">
<span data-bind="text: id"></span>
<input data-bind="value: name" />
<button data-bind="click: dirtyFlag.reset">Reset</button>
</li>
</script>
<button data-bind="enable: isDirty, click: save">Save</button>
<hr />
<h3>Just Dirty Items</h3>
<div data-bind="text: ko.toJSON(dirtyItems)"></div>
CSS
li {
padding: 2px;
margin: 2px;
}
input {
width: 75px;
}
.dirty {
border: solid yellow 2px;
}
JavaScript
ko.dirtyFlag = function(props) {
var result = function() {},
previous = [],
_initialized = ko.observable(false);
result.isDirty = ko.computed(function() {
// grab all subscriptions just the first time through
if (!_initialized()) {
for (let i = 0; i < props.length; i++) {
previous.push(ko.toJS(props[i]()));
}
_initialized(true);
return false;
}
for (let i = 0; i < props.length; i++) {
if (previous[i] != ko.toJS(props[i]()))
return true;
}
return false;
});
result.reset = function() {
previous = [];
_initialized(false);
};
return result;
};
function Item(id, name) {
this.id = ko.observable(id);
this.name = ko.observable(name);
this.dirtyFlag = new ko.dirtyFlag([this.id, this.name]);
}
var viewModel = {
items: ko.observableArray([
new Item(1, "one"),
new Item(2, "two"),
new Item(3, "three")
]),
save: function() {
alert("Sending changes to server: " + ko.toJSON(this.dirtyItems));
}
};
viewModel.dirtyItems = ko.dependentObservable(function() {
return ko.utils.arrayFilter(this.items(), function(item) {
return item.dirtyFlag.isDirty();
});
}, viewModel);
viewModel.isDirty = ko.dependentObservable(function() {
return this.dirtyItems().length > 0;
}, viewModel);
ko.applyBindings(viewModel);