Reputation: 771
What is easiest way to get the contains filter working with a asp.net web api web service that uses odata v4?
It seems that web services using odata v4 no longer acknowledge the 'substringof' function and want the ' contains' function.
Example: GET using the Contains filter on the WorkUnitCode column in the grid and entering 'xYz'. substringof(fails)
http://localhost:1486/odata/BillOfMaterials(2)/BillOfMaterialsItems?$format=json&$top=10&$filter=substringof('xYz',WorkUnitCode)&$count=true
What the GET needs to be for the contains function to work:
http://localhost:1486/odata/BillOfMaterials(2)/BillOfMaterialsItems?$format=json&$top=10&$filter=contains(WorkUnitCode,'xYz')&$count=true
I believe there are two ways to approach this problem and not sure which is better or how given either solution is reusable.
Approach 1: Intercept the request and change it to use the contains function with reversed parameters. Approach 2: Add the substringof functionality to the web api.
Upvotes: 3
Views: 6300
Reputation: 505
Another one bit improved example of the @Ryan Mrachek's answer:
// Let's use 'indexof' instead of 'substringof'
function substringofToIndexof(s) {
s = s.substring(s.indexOf("("));
s = s.substring(1, s.length - 1);
const p = s.split(",");
// Note: TypeScript syntax below
return `indexof(${p[1]},${p[0]}) ge 0`;
}
...
parameterMap: (options, operation) => {
const paramMap = kendo.data.transports.odata.parameterMap(options, operation);
if (paramMap.$filter.startsWith("substringof")) {
paramMap.$filter = substringofToIndexof(paramMap.$filter);
return paramMap;
}
Using Kendo UI With MVC4, WebAPI, OData And EF
Supporting OData Query Options in ASP.NET Web API 2
Using Filter Expressions in OData URIs
Upvotes: 0
Reputation: 9752
Update Since Kendo now supports ODATA V4 there is no longer any need for tweaks to make it work.
Changing the data set type from
type: 'odata'
to
type: 'odata-v4'
Should do the trick. Example source code is here
Upvotes: 10
Reputation: 5189
I have been using this on multiple free text search strings:
paramMap.$filter = paramMap.$filter.replace(/substringof\(('.+?'),(.+?)\)/, "contains($2,$1)");
It allows users to filter on multiple contains expressions. Example:
(Id gt 2 and (substringof('val1',FieldName) or substringof('val2',FieldName)))
// Translates to
(Id gt 2 and (contains(FieldName,'val1') or contains(FieldName,'val2')))
odata-v4 and kendo-grid
Upvotes: 0
Reputation: 186
The version provided by @Gongdo Gong is not perfect, if the expression ends in double parentheses, fails.
Example:
"(Id gt 2 and substringof('desde',Nombre))".replace(/substringof\((.+),(.+)\.)/, "contains($2,$1)")
Returns:
(Id gt 2 and contains(Nombre),'desde'))
The expression needs to be changed:
paramMap.$filter = paramMap.$filter.replace(/substringof\((.+),(.*?)\)/, "contains($2,$1)");
Upvotes: 4
Reputation: 1028
Here's a generalized version of Ryan Mrachek's answer by using regex replace.
parameterMap: function (data) {
var d = kendo.data.transports.odata.parameterMap(data);
if (d.$inlinecount) {
if (d.$inlinecount == "allpages") {
d.$count = true;
}
delete d.$inlinecount;
}
if (d.$filter) {
d.$filter = d.$filter.replace(/substringof\((.+),(.+)\)/, "contains($2,$1)");
}
return d;
}
Upvotes: 4
Reputation: 771
Went with the simpler JS solution where the parameterMap is intercepted and changed to accommodate the new ODATA v4 function.
var ds = new kendo.data.DataSource({
type: 'odata',
serverFiltering: true,
serverPaging: true,
pageSize: 10,
transport: {
read: {
url: function () { return '{0}{1}'.format(_appRoot,_serviceUrl); },
dataType: "json"
}
, parameterMap: function (data) {
var d = kendo.data.transports.odata.parameterMap(data);
delete d.$inlinecount;
d.$count = true;
if (d.$filter) {
// substringof('xYz',WorkUnitCode) needs to
// change to contains(WorkUnitCode,'06')
if (d.$filter.substring(0, 12) == 'substringof(') {
var parms = d.$filter.substring(12, d.$filter.length - 1).split(',');
d.$filter = 'contains({0},{1})'.format(parms[1],parms[0]);
}
}
return d;
}
},
schema: {
data: function (data) { return data.value; },
total: function (data) { return data['@odata.count']; },
model: _schemaModel
}
});
Upvotes: 3