How to use Kendo UI DataSource, Kendo UI Grid with Dynamics CRM 2011 REST Endpoint

Update: the updated post with new sample code can be found here: How to use Kendo UI DataSource, Kendo UI Grid with Dynamics CRM 2011 REST Endpoint Sample 1

The complete source code can be download from sample gallery: Kendo UI DataSource, Kendo UI Grid with Dynamics CRM 2011 REST Endpoint

Kendo UI is a HTML5, jQuery-based framework for building modern HTML apps. Kendo UI combines the best of emerging HTML5, CSS3, and JavaScript technologies with robust, cross-browser techniques to deliver a framework that is both powerfully rich and broadly compatible with older browsers.

Microsoft Dynamics CRM 2011 Release 8 include support for IE, Chrome, Firefox and Safari.

By using a powerful JavaScript framework, the use of ASP.NET is reduced which would remove the complexity of deployment which also makes the solution much more portable.

By using Kendo UI DataSource, Kendo UI Grid with Dynamics CRM 2011 REST Endpoint, it is easy to implement server side filter, sorting and paging.

There are a few tricks to use Kendo UI together with Dynamics CRM 2011 I want to share. The complete code is in the end of this post.

1. Microsoft Dynamics CRM 2011 REST Endpoint does not support $format system query option.

You can use a global jQuery ajax event handler to specifying http header ensures that the results will be returned as JSON.


$(document).ajaxSend(function (e, jqxhr, settings) {
 if (settings.url.toLowerCase().indexOf("XRMServices/2011/OrganizationData.svc".toLowerCase()) >= 0) {
 jqxhr.setRequestHeader("Accept", "application/json");
 }
});

2. Microsoft Dynamics CRM 2011 REST Endpoint does not support $inlinecount, $count system query option.

you can set a function to use fetch xml and soap endpoint to return the total record count.


var dataSource = new kendo.data.DataSource({
 schema: {
 total: function (data) {

var fetchXml = '' +
 '' +
 "" +
 '' +
 '';

var context = GetGlobalContext();

var serverUrl = window.parent.document.location.protocol + '//' + window.parent.document.location.host + '/' + context.getOrgUniqueName();

var _oService = new FetchUtil(context.getOrgUniqueName(), serverUrl);
 var res = _oService.Fetch(fetchXml);

var count = res[0].attributes.count.formattedValue;

return count;
 }
 }
});

3. you need to stop Kendo UI to send default query string parameter and use Dynamics CRM 2011 specific format


var dataSource = new kendo.data.DataSource({
 transport: {
 parameterMap: function (options) {
 return {
 $top: options.take,
 $skip: options.skip,
 $select: 'cgi_name,cgi_postcodeareaId',
 $orderby: options.sort[0].field + ' ' + options.sort[0].dir
 };
 }
 }
});

4. you have to parse returned json object to return object array that Kendo UI understand


var dataSource = new kendo.data.DataSource({
 schema: {
 parse: function (data) {
 return data.d.results;
 },
 type: "json"
 }
});

Complete Kendo UI DataSource code

var dataSource = new kendo.data.DataSource({
    transport: {
        read: {
            url: "http://vmcrm/RECRegistry/XRMServices/2011/OrganizationData.svc/cgi_postcodeareaSet",
            dataType: 'json'
        },
        parameterMap: function (options) {
            return {
                $top: options.take,
                $skip: options.skip,
                $select: 'cgi_name,cgi_postcodeareaId',
                $orderby: options.sort[0].field + ' ' + options.sort[0].dir
            };
        }
    },
    schema: {
        model: {
            id: "cgi_postcodeareaId",
            fields: {
                cgi_name: { type: "string" },
                cgi_postcodeareaId: { type: "string" }
            }
        },
        total: function (data) {

            var fetchXml = '' +
                                           '' +
                                                "" +
                                           '' +
                                       '';

            var context = GetGlobalContext();

            var serverUrl = window.parent.document.location.protocol + '//' + window.parent.document.location.host + '/' + context.getOrgUniqueName();

            var _oService = new FetchUtil(context.getOrgUniqueName(), serverUrl);
            var res = _oService.Fetch(fetchXml);

            var count = res[0].attributes.count.formattedValue;

            return count;
        },
        parse: function (data) {
            return data.d.results;
        },
        type: "json"
    },
    serverPaging: true,
    pageSize: 10,
    serverSorting: true,
    sort: { field: "cgi_name", dir: "asc" }
});

Complete Sample code


    Postcode Areas
<script type="text/javascript" src="../Scripts/jquery.min.js"></script><script type="text/javascript" src="../Scripts/kendo.web.min.js"></script>
<script type="text/javascript" src="../Scripts/FetchUtil.js"></script><script type="text/javascript" src="../../../ClientGlobalContext.js.aspx"></script>
<script type="text/javascript">// <![CDATA[
        var selectedIds = {};

        $(document).ready(function ($) {

            var dataSource = new kendo.data.DataSource({
                transport: {
                    read: {
                        url: "http://vmcrm/RECRegistry/XRMServices/2011/OrganizationData.svc/cgi_postcodeareaSet",
                        dataType: 'json'
                    },
                    parameterMap: function (options) {
                        return {
                            $top: options.take,
                            $skip: options.skip,
                            $select: 'cgi_name,cgi_postcodeareaId',
                            $orderby: options.sort[0].field + ' ' + options.sort[0].dir
                        };
                    }
                },
                schema: {
                    model: {
                        id: "cgi_postcodeareaId",
                        fields: {
                            cgi_name: { type: "string" },
                            cgi_postcodeareaId: { type: "string" }
                        }
                    },
                    total: function (data) {

                        var fetchXml = '<fetch mapping="logical" aggregate="true">' +
                                           '<entity name="cgi_postcodearea">' +
                                                "<attribute name='cgi_postcodeareaid' alias='count' aggregate='count'/>" +
                                           '</entity>' +
                                       '</fetch>';

                        var context = GetGlobalContext();

                        var serverUrl = window.parent.document.location.protocol + '//' + window.parent.document.location.host + '/' + context.getOrgUniqueName();

                        var _oService = new FetchUtil(context.getOrgUniqueName(), serverUrl);
                        var res = _oService.Fetch(fetchXml);

                        var count = res[0].attributes.count.formattedValue;

                        return count;
                    },
                    parse: function (data) {
                        return data.d.results;
                    },
                    type: "json"
                },
                serverPaging: true,
                pageSize: 10,
                serverSorting: true,
                sort: { field: "cgi_name", dir: "asc" }
            });

            var ctlGrid = $("#PostcodeAreaKendoGrid");

            ctlGrid.kendoGrid({
                dataSource: dataSource,
                columns: [{
                    template: '<input type="checkbox" />',
                    sortable: false,
                    width: 9
                },
                {
                    title: 'Postcode Area',
                    field: "cgi_name",
                    width: 120
                }],
                editable: false,
                pageable: true,
                selectable: "multiple, row",
                sortable: {
                    mode: 'single',
                    allowUnsort: false
                },
                dataBound: function () {
                    var grid = this;
                    //handle checkbox change
                    grid.table.find("tr").find("td:first input")
                        .change(function (e) {
                            var checkbox = $(this);
                            var selected = grid.table.find("tr").find("td:first input:checked").closest("tr");

                            grid.clearSelection();

                            //persist selection per page
                            var ids = selectedIds[grid.dataSource.page()] = [];

                            if (selected.length) {
                                grid.select(selected);
                                selected.each(function (idx, item) {
                                    ids.push(grid.dataItem(item).id);
                                });
                            }

                        })
                        .end()
                        .mousedown(function (e) {
                            e.stopPropagation();
                        });

                    //select persisted rows
                    var selected = $();
                    var ids = selectedIds[grid.dataSource.page()] || [];

                    for (var idx = 0, length = ids.length; idx < length; idx++) {
                        var dataItem = grid.dataSource.get(ids[idx]);
                        if (dataItem) {
                            selected = selected.add(grid.table.find("tr[data-uid=" + dataItem.uid + "]"));
                        }
                    }

                    selected
                        .find("td:first input")
                        .attr("checked", true)
                        .trigger("change");

                }
            });

            var grid = ctlGrid.data("kendoGrid");

            grid.thead.find("th:first")
                .append($('<input class="selectAll" type="checkbox"/>'))
                .delegate(".selectAll", "click", function () {
                    var checkbox = $(this);

                    grid.table.find("tr")
                        .find("td:first input")
                        .attr("checked", checkbox.is(":checked"))
                        .trigger("change");
                });
        }).ajaxSend(function (e, jqxhr, settings) {
            if (settings.url.toLowerCase().indexOf("XRMServices/2011/OrganizationData.svc".toLowerCase()) >= 0) {
                jqxhr.setRequestHeader("Accept", "application/json");
            }
        });

// ]]></script></pre>
<div id="PostcodeAreaKendoGrid"></div>
<pre>

Advertisements

4 comments on “How to use Kendo UI DataSource, Kendo UI Grid with Dynamics CRM 2011 REST Endpoint

  1. Thanks for this great example! It’s the first successful CRM/Kendo example I’ve seen. I’m having issues with point #3 above. Is there somewhere I can get more information on the parameterMap options?

  2. Would you please let me know what all things are required if I want to show contact’s first name and last name using Dynamics CRM 2011 Rest endpoint in kendo UI grid?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s