0
votes

I have a selectedCustomer(customer) observable where customer has 3 properties: Fname,LName,Age.

I data-bind those 3 properties to three text inputs and allow the user to edit them. How do I cancel the changes and revert those three properties back to their original state?

I was able to make a clone of it using:

var custCache = ko.observable(ko.mapping.toJS(customer));

I don't want to do manual mapping like below as this can get troublesome when your object has a lot of properites and arrays of other objects.

selectedCustomer().Fname = custCache().Fname;
selectedCustomer().Lname = custCache().Lname;
selectedCustomer().Age= custCache().Age;

So how do I put the values back to customer object when the user cancel the changes? How do I loop those properties and copy them over?

Thanks, Kevin

2

2 Answers

1
votes

Ryan Niemeyer has written about this topic here

However another common approach is to create a knockout extender.

It goes something like this:

ko.extenders.revertable = function(obs, option) {
  // Change this if you want to use something other than _.clone
  // as your clone function
  var cloneFn = _.clone;

  obs.originalValue = cloneFn(obs());
  obs.silentUpdate = ko.observable(false);
  obs.isDirty = ko.observable(false);

  obs.revert = function() {
    obs.silentUpdate(true);
    obs(cloneFn(obs.originalValue));
    obs.silentUpdate(false);
    obs.isDirty(false);
  };

  obs.update = function(value) {
    obs.silentUpdate(true);

    if (_.size(arguments) > 0) {
      obs(value);
    }

    obs.originalValue = cloneFn(obs());
    obs.silentUpdate(false);
    obs.isDirty(false);
  };

  obs.subscribe(function(newValue) {
    if (!ko.unwrap(obs.silentUpdate)) {
      obs.isDirty(true);
    }
  });

  return obs;
}

I used underscore in my example but you can customize it if you're not using underscore in your project.

Use it like this:

var myValue = ko.observable('original');
myValue = myValue.extend({ revertable: {} });

myValue('updated');
myValue.revert();

console.log(myValue()); // logs 'original'
0
votes

Make two observables at the point of building your data:

originalSelectedCustomer = ko.observable(customer);
selectedCustomer = ko.observable(customer);

Bind the second one to the controls so that users input is reflected.

If they cancel you can reset the values with something like:

selectedCustomer(originalSelectedCustomer());

And if they accept, persist the data from selectedCustomer to your storage.

You should probably make your customer object internal properties all observables as well.