Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to clone observables?

What is the best way to clone Observable objects in Knockout to make kind of transactions mechanism?

For example editing this model:

var Action = function (name, ownerType, condition, expression, args) {
    var self = this;
    this.name = ko.observable(name);
    this.ownerType = ko.observable(ownerType);
    this.condition = ko.observable(condition);
    this.expression = ko.observable(expression);
    this.args = ko.observable(args);
};

I want to save state of that object before user will edit it. And if user will cancel editing - rollback object state.

Simplest way is just create another project like:

self.tempAction = new Action(action.name(), action.ownerType(), action.condition(), action.expression(), action.args());

But I'm not sure that it is elegant solution..

So, any ideas?

like image 217
Dmitry Zaets Avatar asked May 10 '12 13:05

Dmitry Zaets


1 Answers

I usually do something like the following:

First I have a function that mimics jQuery's $.extend function. It populates a target object with all of the observable (or non-observable) property values of the source object.

// extends observable objects intelligently
ko.utils.extendObservable = function ( target, source ) {
    var prop, srcVal, isObservable = false;

    for ( prop in source ) {

        if ( !source.hasOwnProperty( prop ) ) {
            continue;
        }

        if ( ko.isWriteableObservable( source[prop] ) ) {
            isObservable = true;
            srcVal = source[prop]();
        } else if ( typeof ( source[prop] ) !== 'function' ) {
            srcVal = source[prop];
        }

        if ( ko.isWriteableObservable( target[prop] ) ) {
            target[prop]( srcVal );
        } else if ( target[prop] === null || target[prop] === undefined ) {

            target[prop] = isObservable ? ko.observable( srcVal ) : srcVal;

        } else if ( typeof ( target[prop] ) !== 'function' ) {
            target[prop] = srcVal;
        }

        isObservable = false;
    }
    return target;
};

Then I have a copy function that essentially converts the object to be copied into JSON and then takes the JSON copy and builds a new javascript object. This ensures all the memory pointers are not copied and you have a brand new object that matches your original one. The one key here is that you do have to pass in an empty instance of a new object (otherwise we would have no idea what properties to populate)

// then finally the clone function
ko.utils.clone = function(obj, emptyObj){
    var json = ko.toJSON(obj);
    var js = JSON.parse(json);

    return ko.utils.extendObservable(emptyObj, js);
};

You can then use it like so:

var tempAction = ko.utils.clone(action, new Action());
like image 144
ericb Avatar answered Oct 19 '22 19:10

ericb