Reputation: 49
I am working on a asp.net MVC project. and i am using knockout.js on my view page. I am trying to develop a data entry grid. Everything works fine except Cancel button.
If i change something on my UI ( view) and clicked on cancel , It is not showing me old values .it only show me the latest values.
Steps:
Right now , even if you edit and click on cancel button , it is able to revert to old state.
I am not going back to old state when i clickd on cancel button. Please suggest me some examples .
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Type Lookup....</title>
<script src="~/Scripts/jquery-2.1.0.js"></script>
<script src="~/Scripts/knockout-3.0.0.js"></script>
<link href="~/Content/Site.css" rel="stylesheet" />
<link href="~/Content/bootstrap.css" rel="stylesheet" />
<script type="text/javascript">
viewModel = {
lookupCollection: ko.observableArray()
};
//wrapper to an observable that requires accept/cancel
ko.protectedObservable = function (initialValue) {
//private variables
var _actualValue = ko.observable(initialValue),
_tempValue = initialValue;
//computed observable that we will return
var result = ko.computed({
//always return the actual value
read: function () {
return _actualValue();
},
//stored in a temporary spot until commit
write: function (newValue) {
_tempValue = newValue;
}
});
//if different, commit temp value
result.commit = function () {
if (_tempValue !== _actualValue()) {
_actualValue(_tempValue);
}
};
//force subscribers to take original
result.reset = function () {
_actualValue.valueHasMutated();
_tempValue = _actualValue(); //reset temp value
};
return result;
};
$(document).ready(function () {
$.ajax({
type: "GET",
url: "/Home/GetIndex",
}).done(function (data) {
$(data).each(function (index, element) {
var mappedItem =
{
Id: ko.observable(element.Id),
Key: ko.observable(element.Key),
Value: ko.observable(element.Value),
Mode: ko.observable("display")
};
viewModel.lookupCollection.push(mappedItem);
});
ko.applyBindings(viewModel);
}).error(function (ex) {
alert("Error.....");
});
$(document).on("click", ".kout-edit", null, function (ev) {
var current = ko.dataFor(this);
current.Mode("edit");
});
$(document).on("click", ".kout-update", null, function (ev) {
var current = ko.dataFor(this);
saveData(current);
current.Mode("display");
});
$(document).on("click", ".kout-cancel", null, function (ev) {
var current = ko.dataFor(this);
current.Mode("display");
});
$(document).on("click", "#create", null, function (ev) {
var current = {
Id: ko.observable(0),
Key: ko.observable(),
Value: ko.observable(),
Mode: ko.observable("edit")
}
viewModel.lookupCollection.push(current);
});
function saveData(currentData) {
var postUrl = "";
var submitData = {
Id: currentData.Id(),
Key: currentData.Key(),
Value: currentData.Value()
};
if (currentData.Id && currentData.Id() > 0) {
postUrl = "/Home/Edit"
}
else {
postUrl = "/Home/Create"
}
$.ajax({
type: "POST",
contentType: "application/json",
url: postUrl,
data: JSON.stringify(submitData)
}).done(function (id) {
currentData.Id(id);
}).error(function (ex) {
alert("ERROR Saving....");
})
}
});
</script>
</head>
<body>
<div>
<p>
<button class="btn btn-primary" id="create">Create</button>
</p>
<table class="table">
<tr>
<th>Key
</th>
<th>Value
</th>
<th>Action
</th>
</tr>
<tbody data-bind="foreach: lookupCollection">
<tr data-bind="template: { name: Mode, data: $data }">
</tr>
</tbody>
</table>
<script type="text/html" id="display">
<td data-bind="text: Key"></td>
<td data-bind="text: Value"></td>
<td>
<button class="btn btn-success kout-edit">Edit</button>
<button class="btn btn-danger kout-delete">Delete</button>
</td>
</script>
<script type="text/html" id="edit">
<td>
<input type="text" data-bind="value: Key" /></td>
<td>
<input type="text" data-bind="value: Value" /></td>
<td>
<button class="btn btn-success kout-update">Update</button>
<button class="btn btn-danger kout-cancel">Cancel</button>
</td>
</script>
</div>
</body>
</html>
Upvotes: 0
Views: 1396
Reputation: 130
Use this
ko.observable.fn.revertable = function () {
var self = this, originalValue = self();
if (!originalValue) {
self.subscribe(function () {
originalValue = originalValue || self();
});
}
self.commit = function () {
originalValue = self();
};
self.revert = function () {
self(originalValue || '');
};
self.isDirty = function () {
return (self() != originalValue);
};
return self;
};
and your observables like this
this.text=ko.observable().revertable();
i assume you have cancel function so in that you can do it like
this.text.revert();
and if you want to save those changes then
this.text.commit();
Upvotes: 1
Reputation: 2399
I have modified your code little bit.
var mappedItem =
{
Id: ko.observable(element.Id),
Key: ko.observable(element.Key),
Value: ko.observable(element.Value),
Mode: ko.observable("display"),
oldData: ko.observable()
};
I have added oldData observable to retain previous data when edit button clicked. So now when you click on cancel data will be restored by "olData" observable. see the below code.
$(document).on("click", ".kout-edit", null, function (ev) {
var current = ko.dataFor(this);
current.oldData(ko.toJS(current));
current.Mode("edit");
});
$(document).on("click", ".kout-update", null, function (ev) {
var current = ko.dataFor(this);
current.oldData(null);
saveData(current);
current.Mode("display");
});
$(document).on("click", ".kout-cancel", null, function (ev) {
var current = ko.dataFor(this);
current.Id(current.oldData().Id);
current.Value(current.oldData().Value);
current.Key(current.oldData().Key);
current.Mode("display");
current.oldData(null);
});
Here is working example on Jsfiddle
Upvotes: 1
Reputation: 3000
You have the protectedObservable in your code, but you're not using it. Turn your 'model' (the data you want to 'cancel') into a protectedObservable. On cancel, call data.reset(). On save, call data.commit().
Little example (not complete):
$(document).on("click", ".kout-cancel", null, function (ev) {
var current = ko.dataFor(this);
current.reset();
current.Mode("display");
});
$(document).on("click", "#create", null, function (ev) {
var current = ko.protectedObservable({
Id: ko.observable(0),
Key: ko.observable(),
Value: ko.observable(),
Mode: ko.observable("edit")
});
viewModel.lookupCollection.push(current);
});
Upvotes: 0