Search code examples
javascriptknockout.jsknockout-mapping-plugin

KnockoutJS: Stop a particular property from setting dirty flag


With some help from StackOverflow community I was able to get my dirty flag implementation to work, based on this example: http://www.knockmeout.net/2011/05/creating-smart-dirty-flag-in-knockoutjs.html

It does exactly what I want, except for a single use case that I don't know how to solve.

Basically I have a select menu that gets automatically populated from the database. This select menu also has an option to make an Ajax call to my back end and have the list of options refreshed, database updated and return the result. This is where things get hairy for me.

First method works fine, however, it has to re-index and re-apply my entire viewModel and takes about 2-3 seconds, running on a local machine with 16gigs of ram and SSD.

jsondata.component.available_tags = result.available_tags;
ko.mapping.fromJS(jsondata, viewModel);

Second method also works, and pretty much instantaneous, however, it sets of isDirty() flag, which I would like to avoid, because this data is already coming from the database and I wont need to save it. I can not use isDirty.reset() method either, because if isDirty was set by something else before I clicked an menu option to update available_tags, it will reset that too. Which I would also like to avoid.

viewModel().component.available_tags(result.available_tags);

My question is: With the first method, can I force UI refresh with ko.mapping.fromJS() on a particular element and not entire dataset? Or, with a second method, can I avoid setting isDirty flag set when available_tags are updated? The twist is that I still need to keep available_tags as an observable, so the select menu is automatically generate/updated.

UPDATE: I was able to update mapping for that one single element with

ko.mapping.fromJS(result.available_tags, {}, viewModel().component.available_tags);

but that immediately set off isDirty flag... Argh


Solution

  • In addition to Tomalak's suggestions, which I totally agree with, maybe the toJSON method can help you out in similar cases where you don't want to split the model. If your dirty flag implementation uses ko.toJSON as a hash function, as Ryan Niemeyer's does, you can give your model (on which the dirty flag is active) a toJSON method, where you do something like this:

    function MyObjectConstructor() {
        this.someProperty = ko.observable();
        this.somePropertyNotUsedInDirtyFlag = ko.observable();
    }
    MyObjectConstructor.prototype.toJSON = function () {
        var result = ko.toJS(this);
        delete result.somePropertyNotUsedInDirtyFlag;
        return result;
    };
    

    Please be aware that this is also used to serialize the object in some other occassions, such as ajax calls. It's generally a handy function for removing computeds and such from your objects before using them in a different context.