2
votes

Is there a way to stop Knockout Mapping from applying a create callback for every nested properties within a model?

Here is an example of the data and mapping passed to ko.mapping.fromJS().

var data = {
    name: 'Scott',
    level1: { 
        name : 'Alice',
        level2: {
            name: 'Tom'
        }
    }
}

var mapping = {
    name: { 
        create: function(options){
            console.log(options);
        }
    }
}

Here is the jsFiddle: http://jsfiddle.net/2LQut/

I want the create function to be called only for the top level, only for "Scott" and not for "Alice" and "Tom".

The only workaround I have found to achieve this is to add this to the create function.

this.create = null;

Is there a better way to do this?

2
I don't have control over the model property names. It is generated from C# objects. - Jason

2 Answers

1
votes

Use the "copy" option. See here: http://knockoutjs.com/documentation/plugins-mapping.html#copying_certain_properties_using_copy

That would be something like this:

var mapping = {
    name: { 
        create: function(options){
            console.log(options);
        }
    },
    copy: "level1"
}
0
votes

Instead of stoppig the create function being called, why not just perform the conditional logic inside it.

You have access to options.parent and options.data so just check to see where you are.

This is using a shopping cart item, but the same principle.

    var mapping =
    {
        'items':
        {
            create: function (options)
            {
                // does the 'item' contain a 'qty' property?
                if (options.data.hasOwnProperty('qty'))
                {
                    return new CartItemViewModel(options.data);
                }
                else 
                {
                    // it must be something else
                    return ko.mapping.fromJS(options.data);
                }
            }
        }
    };

OR for your example

    var mapping =
    {
        'name':
        {
            create: function (options)
            {
                // does the 'parent' contain a 'level1' property?
                if (options.parent.hasOwnProperty('level1'))
                {
                    console.log('we have the name we want');

                    // map it anyway
                    return ko.mapping.fromJS(options.data);
                }
                else 
                {
                    // it must be something else to just map it normally
                    return ko.mapping.fromJS(options.data);
                }
            }
        }
    };