Best way to clone observables?

javascript, knockout.js

Solution

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());

Problem

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?

Original source