How to create dirty flag functionality
I want to create a dirty flag function using knockout. I only want to enable the save button if something has changed. My opinion and my view model is exactly the same as the example found in the js knockout loading and saving tutorial. Link to tutorial
I am following the example script posted by Ryne here
I cannot figure out where to declare below the code that it declared in the view model.
this.dirtyFlag = new ko.dirtyFlag(this);
If I take an example from the knockout tutorial, the link I posted above and I tried like below
function Task(data) {
this.title = ko.observable(data.title);
this.isDone = ko.observable(data.isDone);
this.dirtyFlag = new ko.dirtyFlag(this);
}
Tied my view as below
<button data-bind="click: saveOperation , enable: isDirty" >Save</button>
This is giving me an error as it is not possible to parse the isDirty binding undefined.
I'm not sure how to implement this.
source to share
There are several problems in your code:
-
You define
dirtyFlag
in your functionTask
. But you are checking it against the view associated with the viewModel instance. -
You must define the dirty flag after the one you loaded, or you need to call
dirtyFlag().reset()
. -
isDirty
calculated. You have to call it with parentheses.
The view model looks like this:
function TaskListViewModel() {
// Data
function Task(data) {
this.title = ko.observable(data.title);
this.isDone = ko.observable(data.isDone);
}
var self = this;
self.tasks = ko.observableArray([]);
self.newTaskText = ko.observable();
self.incompleteTasks = ko.computed(function() {
return ko.utils.arrayFilter(self.tasks(), function(task) { return !task.isDone() && !task._destroy });
});
this.dirtyFlag = new ko.DirtyFlag(this.isDone);
// Operations
self.addTask = function() {
self.tasks.push(new Task({ title: this.newTaskText() }));
self.newTaskText("");
};
self.removeTask = function(task) { self.tasks.destroy(task) };
self.save = function() {
$.ajax("/echo/json/", {
data: {
json: ko.toJSON({
tasks: this.tasks
})
},
type: "POST",
dataType: 'json',
success: function(result) {
self.dirtyFlag().reset();
alert(ko.toJSON(result))
}
});
};
//Load initial state from server, convert it to Task instances, then populate self.tasks
$.ajax("/echo/json/", {
data: {
json: ko.toJSON(fakeData)
},
type: "POST",
dataType: 'json',
success: function(data) {
var mappedTasks = $.map(data, function(item) {
return new Task(item);
});
self.tasks(mappedTasks);
self.dirtyFlag().reset();
}
});
}
Undo button binding:
<button data-bind="enable: dirtyFlag().isDirty()">Cancel</button>
And a working fiddle (your fork) can be found at: http://jsfiddle.net/delixfe/ENZsG/6/
source to share
The dirty knockout flag is already implemented in a small library koLite
- https://github.com/CodeSeven/kolite .
Or here's an example of how to create it: http://www.knockmeout.net/2011/05/creating-smart-dirty-flag-in-knockoutjs.html
source to share
There is also a ko.editables plugin: https://github.com/romanych/ko.editables
var user = {
FirstName: ko.observable('Some'),
LastName: ko.observable('Person'),
Address: {
Country: ko.observable('USA'),
City: ko.observable('Washington')
}
};
ko.editable(user);
user.beginEdit();
user.FirstName('MyName');
user.hasChanges(); // returns `true`
user.commit();
user.hasChanges(); // returns `false`
user.Address.Country('Ukraine');
user.hasChanges(); // returns `true`
user.rollback();
user.Address.Country(); // returns 'USA'
source to share