Consuming non-normalized data with the Mapping PlugIn

158 views
Skip to first unread message

Ken Stanfield

unread,
Mar 16, 2012, 5:56:59 PM3/16/12
to KnockoutJS
I have a REST service that returns a collection that contains non-
normalized data. For example, it might look something like this:

root
.
root:CollectionItem[0]
root:CollectionItem[0].alpha
root:CollectionItem[0].beta
root:CollectionItem[0].zappa
.
root:CollectionItem[1].alpha
root:CollectionItem[1].children[1].MoonUnit
root:CollectionItem[1].children[2].Dweezil
root:CollectionItem[1].zappa
.
root:CollectionItem[2]
root:CollectionItem[2].alpha
root:CollectionItem[2].beta
root:CollectionItem[2].zappa

What's the best strategy for using the Mapping PlugIn data like this?
The problem is that it seems to use CollectionItem[0] as a template,
but when I foreach through a result, Knockout is blowing up when I try
to read root.CollectionItem[1].beta (which doesn't exist).



NTB

unread,
Mar 19, 2012, 11:10:24 AM3/19/12
to knock...@googlegroups.com
I dunno about the mapping plugin, but when I come across this situation I usually try to make sure the service passes something that has all the possible fields, even if they're null.  Barring that possibility I have sometimes manually "massaged" the data before calling the mapper, or created a dummy shell object that has all the possible properties set to null (or [] in the case of arrays) -- then use $.extend(dummy, real) to create something .fromJS() can work with.  You'd have to iterate through the array with that pattern, but that's my $.02 anyway.

Would like to hear cleaner solutions myself too though.

var defaultCollectionItem = { alpha: null, beta: null, zappa: null };
$.each( incomingUnmappedItems, function(i, item) { 

NTB

unread,
Mar 19, 2012, 11:11:29 AM3/19/12
to knock...@googlegroups.com
Whoops sorry, left some partially written code at the bottom there.

Ken Stanfield

unread,
Mar 19, 2012, 11:57:41 AM3/19/12
to KnockoutJS
Normalizing the data coming from the RESTful API isn't an option. The
JSON is coming from Mongo DB, so a lot of the data is de-normalized
(which is the point of using a non-relational DB store).

Seems like this is something that *ought* to be supported by the
mapping plug-in itself. I need a way to say: "Here are two templates
for data that *may* be in fooParentNode. Use the right one."

NTB

unread,
Mar 19, 2012, 12:41:02 PM3/19/12
to knock...@googlegroups.com
This may or may not still apply to your situation -- this is the way I do forms too... create a dummy object with null properties for 'add new' mode, and override all the properties with an existing object for 'edit' mode.  

Here's a fiddle http://jsfiddle.net/PxeyY/ .  The whole create view model function can be made into a generic helper function.

Ken Stanfield

unread,
Mar 19, 2012, 6:32:09 PM3/19/12
to KnockoutJS
I'm studying this implementation now. I don't know enough about
Knockout to say whether this will work for me or not, but I really
appreciate you taking the time to give me a working example to play
with! I'll report back once I've had a chance to wrap my head around
your approach.

Thanks again! :-)

Ken Stanfield

unread,
Mar 20, 2012, 12:10:20 PM3/20/12
to KnockoutJS
So, I've studied this example. It's close, but not exactly what I was
looking for. After using your code sample to massage the view and then
calling "ko.mapping.toJS(viewModel)" to unmap the model, here's what
I'm seeing:

unmapped
.
[0].alpha = "alpha1"
[0].beta = "beta1"
[0].zappa = "zappa1"
[0].children = []
.
[1].alpha = "alpha2"
[1].zappa = "zappa2"
[1].children
[1].children[0].moonUnit = "moon1"
[1].children[0].dweezil = null
[1].children[1].dweezil = "dweezil1"
[1].children[1].moonUnit = null
[1].beta = null
.
[2].alpha = "alpha3"
[2].beta = "beta3"
[2].zappa = "zappa3"
[2].children = []

The problem is with the children nodes in [1]. I actually have two
separate children, both of which contain moonUnit and dweezil members,
whereas I only want one instance of each.

The follow-up question I have is this: what would be the recommended
way to "unroll" my modifications to the model either prior to or after
calling "ko.mapping.toJS(viewModel)" ? Essentially, I want to nuke
from the model any member that is either null or an empty array []. In
fact, if I do this, then the problem with the children nodes described
above would go away. I would be nuking the following:

[0].children = []
[1].children[0].dweezil = null
[1].children[1].moonUnit = null
[2].children = []

Ken Stanfield

unread,
Mar 20, 2012, 12:23:34 PM3/20/12
to KnockoutJS
Quick update: I manually nuked null nodes and empty arrays as follows
and ended up with exactly what I was looking for. So, it seems like
the solution is to use a massaging utility function similar to what
NTB provided and then recursively walk through the model and nuke any
node that is either null or an empty array.

Doing this manually, I issued the following commands in my debugger:

delete unmapped[0].children
delete unmapped[1].beta
delete unmapped[1].children[0].dweezil
delete unmapped[1].children[1].moonUnit
delete unmapped[2].children

Thanks!
Reply all
Reply to author
Forward
0 new messages