Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cancel/revert changes to an observable model (or replace model in array with untouched copy)

Tags:

I have a viewModel with an observableArray of objects with observable variables.

My template shows the data with an edit button that hides the display elements and shows input elements with the values bound. You can start editing the data and then you have the option to cancel. I would like this cancel to revert to the unchanged version of the object.

I have tried clone the object by doing something like this:

viewModel.tempContact = jQuery.extend({}, contact);

or

viewModel.tempContact = jQuery.extend(true, {}, contact);

but viewModel.tempContact gets modified as soon as contact does.

Is there anything built into KnockoutJS to handle this kind of situation or am I best off to just create a new contact with exactly the same details and replace the modified contact with the new contact on cancel?

Any advice is greatly appreciated. Thanks!

like image 211
Damien Gabrielson Avatar asked May 03 '11 19:05

Damien Gabrielson


2 Answers

There are a few ways to handle something like this. You can construct a new object with the same values as your current one and throw it away on a cancel. You could add additional observables to bind to the edit fields and persist them on the accept or take a look at this post for an idea on encapsulating this functionality into a reusable type (this is my preferred method).

like image 67
RP Niemeyer Avatar answered Sep 20 '22 16:09

RP Niemeyer


I ran across this post while looking to solve a similar problem and figured I would post my approach and solution for the next guy.

I went with your line of thinking - clone the object and repopulate with old data on "undo":

1) Copy the data object into a new page variable ("_initData") 2) Create Observable from original server object 3) on "undo" reload observable with unaltered data ("_initData")

Simplified JS: var _viewModel; 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);
            });
        });
    });
});

I had an object that was complicated enough that I didn't want to add handlers for each individual property.

Some changes are made to my object in real time, those changes edit both the observable and the "_initData".

When I get data back from the server I update my "_initData" object to attempt to keep it in sync with the server.

like image 38
THammons Avatar answered Sep 19 '22 16:09

THammons