KO mapper and "__ko_mapping__"

2,517 views
Skip to first unread message

nevf

unread,
Apr 14, 2011, 6:05:25 PM4/14/11
to knock...@googlegroups.com
The KO mapper includes a "__ko_mapping__" object in the JSON output. In my use of KO and the mapper I will never be using ko.mapping.updateFromJS() which I assume uses __ko_mapping__. I simply save and reload the entire viewmodel. 

My question is can I safely delete the "__ko_mapping__" object from the viewmodel output before I save the JSON string? 

ex.
        var tvModel = ko.toJS( viewModel );
        delete tvModel.lastSavedJson;
        delete tvModel.__ko_mapping__;      // delete the __ko_mapping__ object.
        var sJson = JSON.stringify( tvModel, null, 4 );
        viewModel.lastSavedJson( sJson );
        // Now save sJson ...

My tests indicate this works just fine. ie. When I map sJson back again.

Or better still have a mapper option to prevent __ko_mapping__ from being created/added in the first place.

The reason for this is that __ko_mapping__ is quite large in my case and I'd rather not have the clutter if it isn't needed.

-Neville

Roy Jacobs

unread,
Apr 15, 2011, 7:57:33 AM4/15/11
to knock...@googlegroups.com
Hi Neville,

Removing it is fine, but the mapping plugin also provides a 'ko.mapping.toJS' you can use which removes any elements that were not part of your original object (such as the __ko_mapping__).
Second, you can skip the JSON stringification and also use 'ko.mapping.toJSON' (and 'ko.toJSON').

Roy

nevf

unread,
Apr 16, 2011, 4:51:34 AM4/16/11
to knock...@googlegroups.com
Hi Roy,
Thanks, just what I need. 

I am having some problems with the mapper, which could be of my making, however I'm leaning on the side of not. I've attached a file which show's the issue. 

The problem occurs after I do ko.mapping.fromJS(), then add a section.item and the save. The two JSON dumps in the file are from the same vewmodel at the same point in time. I've been having problems like this for a few days. I'm sure you'll need more info. The easiest thing for me would be to send you a copy of the app I'm working on. 

Neville
ko_mapper_issue1.txt

Roy Jacobs

unread,
Apr 18, 2011, 8:07:35 AM4/18/11
to knock...@googlegroups.com
Hi Neville,

One thing you need to keep in mind is that 'ko.mapping.toJS' will only take the properties that were part of the original object you used 'fromJS' on. It seems that the object you originally put into 'fromJS' only contained an array "pages", but nothing more. Is that correct?

Roy

nevf

unread,
Apr 18, 2011, 5:16:25 PM4/18/11
to knock...@googlegroups.com
Hi Roy,
No that's not right. The object passed to ko.mapping.toJS()  included all the content in sJson2 except for one (the last) pages.sections.items[] entry. As I mentioned the two JSON dumps in the attached file were produced in the same execution of the code.

This is the sample viewModel I start of with. Then stuff is added in the UI. That's when the mapper output breaks.

        // viewModel Test Data
        var viewModelTestData = {
            app_name: new ko.observable(""),      // Must have value else won't persist in ko.toJSON().
            common_items: {
                background_image_values: new ko.observableArray(["Wash 1", "Wash 2"]),
                background_image: new ko.observable(),
                style_sheet_values: new ko.observableArray(["Image 1", "Button 2"]),
                style_sheet: new ko.observable(),
                text_images: new ko.observableArray([
                    new common_text_image_item( 'Acute', 'Lovely leaf' )
                ]),
                buttons: new ko.observableArray([
                    new common_button_item( "Botanical Terms", "bot_terms" ),
                    new common_button_item( "Leaf Apices" )
                ])
            },
            pages: {
                sections: new ko.observableArray([
                ])
            }
        };

Neville

Roy Jacobs

unread,
Apr 19, 2011, 10:31:25 AM4/19/11
to knock...@googlegroups.com
Hi Neville,

I'm not quire sure what you are trying to do. The mapping plugin works on regular JS objects, not ones that are already populated with observables (as in your viewModelTestData).

Roy

nevf

unread,
Apr 19, 2011, 5:40:17 PM4/19/11
to knock...@googlegroups.com
Hi Roy,
I may have misunderstood what mapping is designed for. I am using it to reload a saved viewmodel. I guess what I really want is to load the model data into the vieModel. 

In my app:
  1. On initial run of the app use the viewModelTestData for the viewModel.
  2. User add's data through the GUI which add's objects to the viewModel.
  3. Save the viewModel using ko.toJSON() or ko.mapping.toJSON() to localstorage.
  4. User closes app, then starts it again.
  5. Read JSON saved in step 3 from localstorage.
  6. Use ko.mapping.fromJSON() to recreate the saved viewModel. This is where things can start to go wrong.
Also note this app is just running on my local PC using file://, not on a Web Server. Not that that should matter.

Neville

Roy Jacobs

unread,
Apr 20, 2011, 3:43:17 AM4/20/11
to knock...@googlegroups.com
Hi Neville,

Well, 'ko.mapping.toJSON' is designed to only work on objects that were created using 'ko.mapping.fromJSON'.
So in your case I think you would have to just use 'ko.toJSON' and  delete the undesirable properties manually.

Roy

nevf

unread,
Apr 20, 2011, 6:42:08 AM4/20/11
to knock...@googlegroups.com
Hi Roy,
Thanks for that. So I use ko.toJS() on my viewModel, then iterate the returned JSON object and delete all __ko_mapping__ keys, then stringify() and save that, I'll be able to use ko.mapping.fromJSON() to recreate my saved viewModel?

Neville

Roy Jacobs

unread,
Apr 20, 2011, 7:10:13 AM4/20/11
to knock...@googlegroups.com
Hi Neville,

If you like, you can indeed use ko.mapping.fromJSON() to convert a JSON string to a viewmodel containing observables.

Roy

nevf

unread,
Apr 20, 2011, 8:20:54 AM4/20/11
to knock...@googlegroups.com
Thanks Roy. Is there some other (possibly better) way to do this?

Neville

Roy Jacobs

unread,
Apr 20, 2011, 9:22:01 AM4/20/11
to knock...@googlegroups.com
I'm afraid I can't really give you an opinion about that since I have quite limited time to look at everything. But if it works, then that's fine!
I'm sure that Ryan (rpn) can produce an elaborate jsfiddle to explore some alternatives :)

nevf

unread,
Apr 21, 2011, 4:47:43 AM4/21/11
to knock...@googlegroups.com
Hi Roy, 
I've added the following to ko.mapping.fromJS() which seems to have solved my issue very nicely.

        // Option to exclude adding mapping properties to returnded viewNodel. NF 21/04/2011
        if ( !options.exclude_mappingProperties ){
   result[mappingProperty] = result[mappingProperty] || {};
   result[mappingProperty] = options;
        }

and then in my code:

    var mapping = { 'exclude_mappingProperties': true,
                     ....
                  };

This makes KO.mapping useful for a slightly different purpose. I for one would appreciate seeing this added in your code.

Apologies for the drawn out discussion. We got there in the end - many thanks for your guidance and patience.

Neville

Roy Jacobs

unread,
Apr 21, 2011, 4:52:43 AM4/21/11
to knock...@googlegroups.com
Hi Neville,

Excellent news! Good to hear you've got it to work.

You can already configure the default properties you would like to ignore by modifying the 'defaultOptions' like so:
ko.mapping.defaultOptions().ignore = ["__ko_mapping__", "someOtherProperty"];

Apologies for not having the documentation up to speed on this, I plan on updating the docs sometime during the easter weekend.

Roy

nevf

unread,
Apr 21, 2011, 5:12:49 PM4/21/11
to knock...@googlegroups.com
Hi Roy,
I did see defaultOptions().ignore however that is only used by ko.mapping.toJS(). My update was to ko.mapping.fromJS() and prevents mapping being added to the viewmodel in the first place.

Another option I'd find very useful  is the ability to specify that certain JSON items did not get turned into observables. I have a number of items that the user can't edit and my code would benefit from these not being observables. I appreciate that this is probably a bit difficult to specify for complex models.

It will be great to see full doc's for the mapping plugin, and even more so for the KO api.

Neville

Roy Jacobs

unread,
Apr 22, 2011, 3:16:50 AM4/22/11
to knock...@googlegroups.com
Hi Neville,

I think adding options to ignore certain properties adds complexity that I'm not sure is warranted. You don't really lose anything from having a few redundant observables and the mapping plugin API can remain simple (and it is complex enough as it is, I believe). In your scenario, the view would be responsible for making sure an item cannot be edited, not the fact that it is observable or not, right?

Roy

Roy Jacobs

unread,
Apr 22, 2011, 5:39:05 AM4/22/11
to knock...@googlegroups.com
By the way, didn't I promise that rpn (Ryan) would probably do some examples?
Well, guess what? :)


Thanks rpn!

nevf

unread,
Apr 22, 2011, 7:12:57 PM4/22/11
to knock...@googlegroups.com
Hi Roy,
I agree this probably isn't warranted. But it would still be nice. ;-)

Neville

nevf

unread,
Apr 22, 2011, 7:14:37 PM4/22/11
to knock...@googlegroups.com
Hi Roy, 
Any thoughts on including my:  ko.mapping.fromJS() options.exclude_mappingProperties update?

Neville

Roy Jacobs

unread,
May 2, 2011, 6:19:41 AM5/2/11
to knock...@googlegroups.com
Hi Neville,

Just to iterate the use-case: This would then be for situations where you use ko.mapping.fromJS to create a viewmodel and you then explicitly NOT use ko.mapping.toJS/toJSON (but instead use ko.toJS/toJSON or equivalent) to convert it back to a regular object?

Roy
Reply all
Reply to author
Forward
0 new messages