Question

I'm trying to enable case insensitive filtering (server side) for a kendo grid. Does anyone know a way to inject tolower (toupper, etc) into the filter to enable case insensitive filtering?

Background:

I dropped a kendo grid in to consume data from a controller (EntitySetController, .NET 4.5) and all seems to work very well. Inline editing, server paging, adding new rows, etc.

To enable case insensitive filtering with knockout, I would just build the filter with the filter text and field wrapped in tolower (as recommended here). I haven't found a way to customize the filter using kendo elements.

Controller:

public class CategoriesController : EntitySetController<Category, int>
{
    public override IQueryable<Category> Get()
    {
        return _repository.Find().OrderBy(c => c.Name);
    }
}

Data source creation:

var serviceBaseUrl = "api/Categories",
    dataSource = new kendo.data.DataSource({
        type: "odata",
        transport: {
            read: {
                url: serviceBaseUrl,
                dataType: "json"
            }
        },
        schema: {
            // omitted for brevity
        },
        serverFiltering: true,
        serverPaging: true,
        pageSize: 10
});

Grid creation:

$("#grid").kendoGrid({
    dataSource: dataSource,
    pageable: true,
    filterable: {
        extra: false,
        operators: {
            string: {
                contains: "Contains",
            }
        }
    },
    columns: [
        // omitted for brevity
    ]
});
Was it helpful?

Solution

Based on the total lack of response, I'm guessing very few other people ran into this issue and didn't see the obvious solution I finally came up with. Just in case some other poor soul is stuck like I was, here is what I came up with.

The transport object on the data source needs a function called parameterMap. In that, do something like the following:

parameterMap: function (data, type) {
    if (type == "read") {
        if (nameFilter) { // pull nameFilter from a viewmodel or wherever
            data.filter = {
                field: "tolower(Name)",
                operator: "contains",
                value: nameFilter.toLowerCase()
            };
        }

        var newData = kendo.data.transports.odata.parameterMap(data);
        delete newData.$format; // not currently supported by webapi.
        return newData;
    }
},

I did some simplifying for purposes of this answer, so apologies if that example is broken. I did my best to make it actually functional.

OTHER TIPS

do it Server side for all operations by downloading the code from https://github.com/telerik/kendo-examples-asp-net

and changing QueryableExtensions.cs function Filter

to this

    private static IQueryable<T> Filter<T>(IQueryable<T> queryable, Filter filter)
    {
        if (filter != null && filter.Logic != null)
        {
            // Collect a flat list of all filters
            var filters = filter.All();

            // Get all filter values as array (needed by the Where method of Dynamic Linq)
            var values = filters.Select(f => f.Value is string ? f.Value.ToString().ToLower() : f.Value).ToArray();

            //Add toLower() for all filter Fields with type of string in the values 
            for (int i = 0; i < values.Length; i++)
            {
                if (values[i] is string)
                {
                    filters[i].Field = String.Format("{0}.ToString().ToLower()", filters[i].Field);
                }
            }
            // Create a predicate expression e.g. Field1 = @0 And Field2 > @1
            string predicate = filter.ToExpression(filters);


            // Use the Where method of Dynamic Linq to filter the data
            queryable = queryable.Where(predicate, values);
        }

        return queryable;
    }

I know this is an old question, but I think this should be a useful solution for others who are looking for an answer:

parameterMap: function (options, operation) {
    if (operation == "read") {
        if (options.filter) {
            //console.log(`options: ${JSON.stringify(options)}`);

            var newFilter = {
                logic: options.filter.logic,
                filters: []
            };

            $.each(options.filter.filters, function (index, filter) {
                var fieldName = filter.field;
                var fieldType = $('#grid').data("kendoGrid").dataSource.options.schema.model.fields[fieldName].type;
                //console.log(`field: ${fieldName} has type: ${fieldType}`);

                if (fieldType == "string") {
                    var newFilterField = {
                        field: `tolower(${filter.field})`,
                        operator: filter.operator,
                        value: filter.value.toLowerCase()
                    };
                    newFilter.filters.push(newFilterField);
                }
                else {
                    newFilter.filters.push(filter);
                }
            });

            options.filter = newFilter;
        }

        var paramMap = kendo.data.transports["odata-v4"].parameterMap.call(this, options, operation);
        return paramMap;
    }
}

Note that I did see an ignoreCase option in the columns. Here's an example (taken from columns.filterable.ignoreCase):

$("#grid").kendoGrid({
    columns: [{
        field: "country",
        filterable: {
            multi: true,
            search: true,
            ignoreCase: true // <-- Here
        }
    }],
    filterable: true,
    dataSource: [{ country: "BG" }, { country: "USA" }]
});

However, that doesn't seem to do anything.. at least when using OData anyway.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top