Me encontré con esta publicación mientras buscaba resolver un problema similar y pensé que publicaría mi enfoque y solución para el siguiente tipo.
Fui con su línea de pensamiento - clonar el objeto y repoblar con datos antiguos en "deshacer":
1) copia del objeto de datos en una página nueva variable ("_initData") 2) Crear observable desde el objeto servidor original 3) en "deshacer" recargar observable con los datos inalterados ("_initData")
simplificado JS: _viewModel var; var _initData = {};
$(function() {
//on initial load
$.post("/loadMeUp", {}, function (data) {
$.extend(_initData , data);
_viewModel = ko.mapping.fromJS(data);
});
//to rollback changes
$("#undo").live("click", function(){
var data = {};
$.extend(data, _initData);
ko.mapping.fromJS(data, {}, _viewModel);
});
//when updating whole object from server
$("#updateFromServer).live("click", function(){
$.post("/loadMeUp", {}, function (data) {
$.extend(_initData , data);
ko.mapping.fromJS(data, {}, _viewModel);
});
});
//to just load a single item within the observable (for instance, nested objects)
$("#updateSpecificItemFromServer).live("click", function(){
$.post("/loadMeUpSpecificItem", {}, function (data) {
$.extend(_initData.SpecificItem, data);
ko.mapping.fromJS(data, {}, _viewModel.SpecificItem);
});
});
//updating subItems from both lists
$(".removeSpecificItem").live("click", function(){
//object id = "element_" + id
var id = this.id.split("_")[1];
$.post("/deleteSpecificItem", { itemID: id }, function(data){
//Table of items with the row elements id = "tr_" + id
$("#tr_" + id).remove();
$.each(_viewModel.SpecificItem.Members, function(index, value){
if(value.ID == id)
_viewModel.SpecificItem.Members.splice(index, 1);
});
$.each(_initData.SpecificItem.Members, function(index, value){
if(value.ID == id)
_initData.SpecificItem.Members.splice(index, 1);
});
});
});
});
Tenía un objeto lo suficientemente complicado como para no querer agregar controladores para cada propiedad individual.
Algunos cambios se realizan en mi objeto en tiempo real, esos cambios editan tanto el observable como el "_initData".
Cuando recibo datos del servidor actualizo mi objeto "_initData" para intentar mantenerlo sincronizado con el servidor.
¡Gracias, Ryan! Leí un par de publicaciones en su sitio hoy, pero de alguna manera me perdí esa. ¡Buen material! – gabrielsond
¡Gracias! Estoy usando este código ahora y funciona muy bien. Modifiqué para hacer que el tempvalue también fuera observable. También agregué un cálculo para verificar si el protectedObservable estaba sucio. – Gunslinger