3
\$\begingroup\$

I am using knockout in my project. I have some models like EmployeeModel, ServiceModel etc which user can update. On UI I give the user a Cancel control button by which he can revert the changes. On cancel I have to revert the model change back to its original state. For this I found these two good approaches by @rniemeyer:

Protected Observable

I can't use protected observables because I am using ko.mapping plugin which will create a knockout models base on server side viewmodels. Yes, I can use mapping option like Create, but I feel its not a good to keep separate observables state. I want solution which will be reusable and can apply to whole model.

And guess what I got, second good approach by same author @rniemeyer:

Simple editor pattern

I can't use this also because of the same reason I mentioned above. So I wrote 2 functions copy and reset which will do the job for me:

Copy

Here, source is the object whose current state we want to preserve, and dest keeps the current state.

function copy(source, dest) {

    for (var key in source) {

        if (source.hasOwnProperty(key)) {

            //no need to keep knockout added properties
            if (key === "__ko_mapping__")
                continue;

            //recursive call to copy if property is an object
            else if (typeof source[key] === "object") {
                dest[key] = {};
                copy(source[key], dest[key]);
            }

            else {
                //no need to copy the computed observable value
                if (!ko.isComputed(source[key])) {
                    var value = ko.utils.unwrapObservable(source[key]);
                    dest[key] = value;
                }
            }
        }
    }

    //remove all function
    for (var key in dest) {
        if (typeof dest[key] === "function")
            delete dest[key];
    }
}

Reset

Here, source is the previous dest and dest is the previous source.

function reset(source, dest) {

    for (var key in source) {

        if (source.hasOwnProperty(key)) {

            //recursive call to copy if it is an object
            if (source[key] !== null && typeof source[key] === "object") {
                reset(source[key], dest[key]);
            }

            else {
                if (ko.isObservable(dest[key]))
                    dest[key](source[key]);
                else
                    dest[key] = source[key];
            }
        }
    }
}

I want you to please review these function and let me know if these function require any improvement.

\$\endgroup\$
3
\$\begingroup\$

From a KISS perspective, I would simply load the model again, then you would not need any of this code.

Other than that the code is clean and maintainable, some nitpicking though:

  • You declare var key twice in copy, that is not required
  • You are not using hasOwnProperty(key) when you delete all the functions in copy
  • You could have merged source.hasOwnProperty(key) and key === "__ko_mapping__" with a &&
  • You access source[key] a lot, you could have considered a var value = source[key] and then work with value
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.