7 Answers, 1 is accepted

Apologies - please delete this post.

Ok I am not actually this crazy normally... I thought I had got this working but that is not the case.
The Multi Filter Checkboxes now appear for the dropdown columns however, they contain ALL possible dropdown values and not just the values that are in the grid.
Is there anyway to restrict this so that it behaves like the other multi filter checkboxes?
In general, you will need to enable the "Multi" option, telling the grid to use MultiCheck widget as a filter menu for the particular column. You can see this in our online "Filter multi checkboxes" demo:
In general, the MultiCheck widget will filter the items internally in order to display distinct ones. If you are using a remote binding, then you will need to return the unique values manually. Please refer to the "Filter_Multi_CheckboxesController.cs" file, in the aforementioned online demo.
Regards,
Georgi Krustev
Telerik

Hi Georgi,
I am using remote binding, however I need the Filter Checkboxes datasource to be re-bound any time the grid is filtered. To complicate matters further, I have pagination enabled on the grid. So I need the filter menus to use distinct values from the entire dataset, not just page 1, and to also take in to account any filtering already applied to the grid.
Thanks
Barry
Basically, when widget uses remote binding, then the server will need to handle the filtration, pagination and etc. That being said, the MultiCheck will send the required parameters to the server and the service in question should return only the correct data set.
The local binding, requires to update the widget manually as it is shown in this Dojo demo.
If I am missing something in the question or you are experiencing any difficulties with the implementation, please send us a repro demo that demonstrates the issue. Thus we will be able to review it locally and advice you further.
Regards,
Georgi Krustev
Telerik

I figured out how I needed to do this. So for anyone else who may have the problem... here is my solution.
I added a custom data attribute to my grid headers to identity whether my custom multi filter should be used:
.HeaderHtmlAttributes(
new
{ data_multi_filter = ​
"True"
})
I then hooked up to the FilterMenuInit event on the grid:
.Events(ev => ev.FilterMenuInit(
"GridFilterMenuInitialized"
)
My JS Function for FilterMenuInit looks like this:
function
GridFilterMenuInitialized(e) {
var
popup = e.container.data(
"kendoPopup"
);
var
parent = popup.options.anchor.parent();
var
fieldName = parent.data(
"field"
);
var
gridDataSource =
this
.dataSource;
var
currentFilters;
if
(gridDataSource.filter())
{
// Transform the filters that have been applied in the grid to a long string
currentFilters = gridDataSource.transport.parameterMap({filter: gridDataSource.filter()}).filter;
}
if
(parent.data(
"multi-filter"
) ==
"True"
)
{
// Only do this for multi-filters
// Leave the default filter for everything else
// Grab an element in the DOM that we can attach our listview too
var
helpTextElement = $(e.container).children(
":first"
).children(
":first"
);
// Destroy and remove any Kendo List View widget already created for this field
var
isCreated = $(
'#lst'
+fieldName)
if
(isCreated.data(
"kendoListView"
))
{
isCreated.data(
"kendoListView"
).destroy();
}
if
(isCreated)
{
isCreated.remove();
}
// Create an instance of a listview
// We don't actually bind to anything here
// It is done on the fly in the popup open event (see further down)
var
element = $(
"<div id='lst"
+ fieldName +
"' class='checkbox-container'></div>"
).insertAfter(helpTextElement).kendoListView({
dataSource:
null
});
// Hide all those other dropdown and filtering stuff
$(
'.checkbox-container'
).siblings(
"span"
).hide()
$(
'.checkbox-container'
).siblings(
"input"
).hide()
// Hook up the Filter event
e.container.find(
"[type='submit']"
).click(
function
(e) {
e.preventDefault();
e.stopPropagation();
// Apply whatever have been checked in the checkbox list to the grid
var
filter =gridDataSource.filter() || { logic:
"and"
, filters: [] };
var
fieldFilters = $.map($(element).find(
":checkbox:checked"
),
function
(input) {
return
{
field: fieldName,
operator:
"eq"
,
value: input.value
};
});
if
(fieldFilters.length) {
removeFiltersForField(filter, fieldName);
filter.filters.push({
logic:
"or"
,
filters: fieldFilters
});
gridDataSource.filter(filter);
}
popup.close();
});
// Hookup the Clear button event
e.container.find(
"[type='reset']"
).click(
function
(e) {
e.preventDefault();
e.stopPropagation();
// clear whatever have been checked in the checkbox list to the grid
var
filter =gridDataSource.filter() || { logic:
"and"
, filters: [] };
var
fieldFilters = $.map($(element).find(
":checkbox:checked"
),
function
(input) {
return
{
field: fieldName,
operator:
"eq"
,
value: input.value
};
});
if
(fieldFilters.length) {
removeFiltersForField(filter, fieldName);
gridDataSource.filter(filter);
}
popup.close();
});
// bind to the popup open event and do some custom work for multifilters
e.container.data(
"kendoPopup"
).bind(
"open"
,
function
(e) {
if
(gridDataSource.filter())
{
// Transform the filters that have been applied in the grid to a long string
currentFilters = gridDataSource.transport.parameterMap({filter: gridDataSource.filter()}).filter;
}
if
(parent.data(
"multi-filter"
) ==
"True"
)
{
// This is a multi filter lets do some custom stuff
var
checkboxesDataSource;
// It's multi filter
checkboxesDataSource =
new
kendo.data.DataSource({
transport: {
read: {
url:
'@Url.Action("GetMultiFilterOptionsForColumn")'
,
dataType:
"json"
,
data: { field: fieldName, currentFilters: currentFilters }
}
});
}
// Grab the current ListView
var
lst = $(
"#lst"
+ fieldName).data(
"kendoListView"
);
var
lstOptions = lst.options;
// Rebind the datasource
// This is important as the current filters and/or fieldname may have changed.
lstOptions.dataSource = checkboxesDataSource;
// rebind the template
lstOptions.template =
"<div><input type='checkbox' #: check # value='#: fieldvalue #'/>#: fieldtext #</div>"
;
// Destroy the current listview
lst.destroy();
// and recreate it with the updated datasource options
// this will initiate a .dataSource.transport.read() call to the specified URL
$(
"#lst"
+ fieldName).kendoListView(lstOptions);
$(
"#lst"
+ fieldName).css({
"height"
:
"300"
,
"width"
:
"200"
,
"overflow"
:
"scroll"
});
}
});
}
}
// Helper function for filtering
function
removeFiltersForField(expression, field) {
if
(expression.filters) {
expression.filters = $.grep(expression.filters,
function
(filter) {
removeFiltersForField(filter, field);
if
(filter.filters) {
return
filter.filters.length;
}
else
{
return
filter.field != field;
}
});
}
}
In my Controller I have the following method:
public
ActionResult GetMultiFilterOptionsForColumn(
string
field,
string
currentFilters)
{
// This gets the possible distinct values for the CURRENT grid items.
currentFilters = currentFilters ??
""
;
DataSourceRequest request =
new
DataSourceRequest();
request.Filters = Kendo.Mvc.Infrastructure.FilterDescriptorFactory.Create(currentFilters ==
null
?
""
: currentFilters.ToString());
// Here you would call you service/repo and get the data that you need
// to display dynamically in the filter options.
// In my case I am returning a list of string values
var values = _serviceObject.CallMethodToGetAllDistinctDataValues(field, request);
// Construct a new anonymous type to be consumed by the filter menu (converting NULLS to string values)
var arr = values.Select(c =>
new
{ fieldvalue = (c ==
null
?
"NULL"
: c.ToString()),
fieldtext = (c ==
null
?
"NULL"
: c.ToString()),
check = currentFilters.Contains(field) ==
true
?
"checked"
:
""
}).ToArray();
return
Json(arr, JsonRequestBehavior.AllowGet);
}
What happens here is that any column header with the data attribute multi-filter will have a custom checkbox list with the items returned from the controller method. The call to the controller is made when the filter popup opens. There is additional custom code to hook up the Filter and Clear buttons.
If a column does not have the custom data attribute of multi-filter then the default Kendo Filter is displayed.
I hope this helps someone else, please do let me know if there are any errors or a misunderstanding of how things work!
Thanks
Barry

Hi Barry
Excellent work but can you please give us the code for var values = _serviceObject.CallMethodToGetAllDistinctDataValues(field, request);
Many thanks