Search code examples
knockout.jskendo-uikendo-gridodataknockout-kendo

Kendo-Knockout: How to filter and sort a remote data source?


I am trying to get KendoGrid and Knockout JS working together. So far, so good.. except that I don't know how to get filtering and sorting working with a remote data source (I don't want to load all of the data on the client side before being able to sort and filter it.). Here's what I have so far:

MARKUP

<div class="row">
    <div id="Grid" data-bind="kendoGrid: Records"></div>
</div>

JS

var PageVM = function (model) {
    model = model || {};
    var self = this;
    self.Id = ko.observable(model.Id || 0);
    self.Title = ko.observable(model.Title || '');
    self.Slug = ko.observable(model.Slug || '');
    self.MetaKeywords = ko.observable(model.MetaKeywords || '');
    self.MetaDescription = ko.observable(model.MetaDescription || '');
    self.IsEnabled = ko.observable(model.IsEnabled || false);
    self.BodyContent = ko.observable(model.BodyContent || '');
    self.CssClass = ko.observable(model.CssClass || '');
    self.CultureCode = ko.observable(model.CultureCode || '');
}

var ViewModel = function () {
    var self = this;
    self.Records = ko.observableArray([]);

    self.Refresh = function () {
        OData.read({
            requestUri: "/odata/cms/Pages"
        },
        function (data, response) {
            viewModel.Records([]);
            $.each(data.results, function () {
                var pageVM = new PageVM(this);
                viewModel.Records.push(pageVM);
            });
        },
        function (e) {
            alert(e.message);
        });
    };

    self.Edit = function () {
        alert("test");
    };

    ko.bindingHandlers.kendoGrid.options = {
        pageable: {
            refresh: true
        },
        scrollable: false,
        columns: [{
            field: "Title",
            title: "Title"
        }, {
            field: "Slug",
            title: "Slug"
        },{
            field: "IsEnabled",
            title: "IsEnabled"
        },{
            field: "Id",
            title: " ",
            template: '<a onclick="edit()" class="btn btn-default btn-sm">Edit</a> <a href="Delete/#=Id#" class="btn btn-danger btn-sm">Delete</a>'
        }]
    };
};

var viewModel;

$(document).ready(function () {
    viewModel = new ViewModel();
    viewModel.Refresh();
    ko.applyBindings(viewModel);
});

function edit() {
    alert("test");
}

As you can see, I am using OData. As for the kendoGrid knockout binding, that's coming from here: http://rniemeyer.github.io/knockout-kendo/web/Grid.html

I guess what I need to do is probably get the filters and sorts from the KendoGrid itself first and then manually append that to an odata query string. I would also manually have to tell Kendo the total number of pages so it knows how many page numbers to display in the grid.

So, I think I know what needs to be done, but I don't know where to start (how do I get/set such data with the KendoGrid, for example?).


Solution

  • After many hours trying to make this work, I ended up deciding on a simpler solution: use the KendoGrid with the OData source directly and then only use Knockout for creating and editing single entries (it doesn't need to be aware of all entries in the grid).

    This also took a while to figure out though.. the following link was a good start: http://blogs.telerik.com/kendoui/posts/12-10-25/using_kendo_ui_with_mvc4_webapi_odata_and_ef

    However, it didn't give me all the answers I needed. For example, I needed to figure out that ASP.NET Web API uses the property value for the data and odata.count for the total number of records. Here is my final implementation (minus the knockout stuff):

    $(document).ready(function() {
        $("#Grid").kendoGrid({
            data: null,
            dataSource: {
                type: "odata",
                transport: {
                    read: {
                        url: "/odata/cms/Pages",
                        dataType: "json"
                    }
                },
                schema: {
                    data: function (data) {
                        return data.value;
                    },
                    total: function (data) {
                        return data["odata.count"];
                    }
                },
                pageSize: 10,
                serverPaging: true,
                serverFiltering: true,
                serverSorting: true
            },
            filterable: true,
            sortable: true,
            pageable: {
                refresh: true
            },
            scrollable: false,
            columns: [{
                field: "Title",
                title: "Title"
            }, {
                field: "Slug",
                title: "Slug"
            },{
                field: "IsEnabled",
                title: "Is Enabled"
            },{
                field: "Id",
                title: " ",
                template: '<a onclick="editRecord(#=Id#)" class="btn btn-default btn-sm">Edit</a> <a onclick="deleteRecord(#=Id#)" class="btn btn-danger btn-sm">Delete</a>'
            }]
        });
    });