Reputation: 658
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
]
});
Upvotes: 3
Views: 7674
Reputation: 6963
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.
Upvotes: 1
Reputation: 31
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;
}
Upvotes: 3
Reputation: 658
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.
Upvotes: 10