This is a migrated thread and some comments may be shown as answers.

parameterMap for objects with multiple Arrays (Composite pattern) for ASP.NET MVC 3

1 Answer 134 Views
Data Source
This is a migrated thread and some comments may be shown as answers.
Reinhard
Top achievements
Rank 1
Reinhard asked on 15 Mar 2012, 01:35 PM
We are using kendoUI - dataSource to hold objects, that are implemented with composite pattern. Those build up a tree-structure using multiple arrays. Our object looks like this:

public class FilterConstraint
    {
        public Guid Id { get; set; }
        public Operator Op { get; set; }
        public string Field { get; set; }
        public string Value { get; set; }
        [XmlArray("FilterConstraints")]
        [XmlArrayItem("FilterConstraint")]
        public List<FilterConstraint> FilterConstraints { get; set; }
}

Transferring this object from javascript back to MVC3 caused problems on server-side binding.
We found a solution within the kendoUI_TodoList Sample. They used the parameterMap within the transport configuration item on the datasource to map response for MVC3-Databinding:

parameterMap: function (data, type) {
    if (type != "read") {
        var items = {};
 
        $.each(data.models, function (index, item) {
            for (var key in item) {
                items["[" + index + "]" + "." + key] = item[key];
            }
        });
 
        return items;
    }
},

Nice solution, but it is just working for the first level of the tree. Therefore we came up with a recursive solution, we want to share with you. Just insert the following code snippet inside the transport configuration item of your datasource:

recursiveParameterMap: function (models, items, parentArray, context) {
    $.each(models, function (index, item) {
        for (var key in item) {
            if (item[key] != null && item[key].push) {
                context.options.recursiveParameterMap(item[key], items, parentArray + "[" + index + "]" + "." + key, context);
            }
            else {
                items[parentArray + "[" + index + "]" + "." + key] = item[key];
            }
        }
    });
},
parameterMap: function (data, type) {
    if (type != "read") {
        var items = {};
        this.options.recursiveParameterMap(data.models, items, "", this);
        return items;
    }
},

Hopefully this helps someone out there ;-)

best regards,
Reinhard and Stefan

1 Answer, 1 is accepted

Sort by
0
Robert
Top achievements
Rank 1
answered on 18 May 2012, 08:37 PM
Hey guys,

Thanks for this, it was a huge lifesaver. But there is a problem, in that it does not handle dates the way MVC expects. It sends them back in the Kendo format, which is known as a "ruby string".

I had to make some modifications to this function, so I thought I'd pass them along. First, you'll need these helper functions:
if (typeof String.prototype.startsWith != 'function') {
    String.prototype.startsWith = function (str) {
        return this.slice(0, str.length) == str;
    };
}
 
if (typeof String.prototype.endsWith != 'function') {
    String.prototype.endsWith = function (str) {
        return this.slice(-str.length) == str;
    };
}

Then, you'll need to grab moment.js, which is a great library for dealing with dates in Javascript. Once you have that, you can make the following modification the changes are in the 'else' part):

recursiveParameterMap = function(models, items, parentArray, context) {
    $.each(models, function(index, item) {
        for (var key in item) {
            if (item[key] != null && item[key].push) {
                context.options.recursiveParameterMap(item[key], items, parentArray + "[" + index + "]" + "." + key, context);
            } else {
                var result = item[key];
                if (key.toLowerCase().startsWith("date") || key.toLowerCase().endsWith("date")) {
                    result = moment(result).format("MM/DD/YYYY");
                }
                items[parentArray + "[" + index + "]" + "." + key] = result;
            }
        }
    });
};

This assumes that your date properties will have "Date" at the beginning or the end. Your mileage may vary. With this change, you can successfully post to MVC, and the ModelBinder will understand it as a date, without having to pass up the string and use a JsonDeserializer.

Anyways, HTH.
Tags
Data Source
Asked by
Reinhard
Top achievements
Rank 1
Answers by
Robert
Top achievements
Rank 1
Share this question
or