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

2 posts, 0 answers
  1. Reinhard
    Reinhard avatar
    1 posts
    Member since:
    Nov 2010

    Posted 15 Mar 2012 Link to this post

    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
  2. Robert
    Robert avatar
    38 posts
    Member since:
    Feb 2012

    Posted 18 May 2012 Link to this post

    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.
  3. Kendo UI is VS 2017 Ready
Back to Top