I've got a Column with String Values!
Our Customer wants to filter this Column with Checkboxes (like it is in Excel > look 'filter_checkbox-excel.png' attached) based on the Values of the Column and with "or"-Functionality! I've added a Screenshot oft the Design (filter_checkbox-web.png), how it should look like - can anyone say if this is possible?
greetings from Austria
Flo
30 Answers, 1 is accepted
This is not supported but it is possible to implement it by using filterable ui function or the filterMenuInit event to modify the filter menu elements. I created an example that demonstrates one possible implementation with the filterMenuInit event.
Regards,
Daniel
Telerik
Your Code is working partly in my solution "out of the box"! I just had to do some adjustments!
Greetings from Austria
Flo
How would you take this a step further to update the filter list in an editable grid where the user creates, edits, or delete an item?
I created an example that demonstrates how to update the filter items when the grid dataSource is changed.
Regards,
Daniel
Telerik
Do you know if there is a filter menu close event? I need to reset the checkboxes in case the user changes their selections but then never clicks on the filter or clear button and just closes the menu.
The popup used by the filter menu has a close event:
function
initCheckboxFilter(e) {
e.container.data(
"kendoPopup"
).bind(
"close"
,
function
(e) {
//your logic
});
Regards,
Daniel
Telerik
Screen 1 shows filtering of the column "Model"
Screen 2 should have filtering for both "Model" and "Software" but as you can see from the query string parameters its only showing filters for "Software". This filter should return 0 items as the 2 Models checked do not have software with that version.
Your source code I am using:
var filter = dataSource.filter() || { logic: "and", filters: [] };
var fieldFilters = element.find(":checkbox:checked").map(function (idx, input) {
return {
field: field,
operator: "eq",
value: input.value
};
});
if (fieldFilters.length) {
removeFiltersForField(filter, field);
filter.filters.push({
logic: "or",
filters: fieldFilters
});
dataSource.filter(filter);
}
});
@(Html.Kendo().Grid<
EndpointViewModel
>()
.Name("grid-inventory")
.Columns(columns =>
{
columns.Bound(inventoryList => inventoryList.SiteName).Title(PhoenixLocalization.Inventory.List.Site).Filterable(false);
columns.Bound(inventoryList => inventoryList.SiteName).Title(PhoenixLocalization.Inventory.List.Type).Filterable(false);
columns.Bound(inventoryList => inventoryList.EndpointModelName).Title(PhoenixLocalization.Inventory.List.Model);
columns.Bound(inventoryList => inventoryList.OwnerName).Title(PhoenixLocalization.Inventory.List.Owner).Filterable(false);
columns.Bound(inventoryList => inventoryList.SoftwareVersionTypeName).Title(PhoenixLocalization.Inventory.List.Software);
columns.Bound(inventoryList => inventoryList.SerialNumber).Title(PhoenixLocalization.Inventory.List.SN).Filterable(false);
columns.Bound(inventoryList => inventoryList.E164Number).Title(PhoenixLocalization.Inventory.List.E164).Filterable(false);
columns.Bound(inventoryList => inventoryList.IpAddress).Title(PhoenixLocalization.Inventory.List.IP).Filterable(false);
columns.Bound(inventoryList => inventoryList.ISDNVideoNumber).Title(PhoenixLocalization.Inventory.List.ISDN).Filterable(false);
columns.Bound(inventoryList => inventoryList.H323Alias).Title(PhoenixLocalization.Inventory.List.H323).Filterable(false);
columns.Bound(inventoryList => inventoryList.GKIp).Title(PhoenixLocalization.Inventory.List.GKIP).Filterable(false);
columns.Bound(inventoryList => inventoryList.SipServerIP).Title(PhoenixLocalization.Inventory.List.SIP).Filterable(false);
columns.Bound(inventoryList => inventoryList.Managed).Title(PhoenixLocalization.Inventory.List.Managed).Filterable(false);
columns.Bound(inventoryList => inventoryList.SipURI).Title(PhoenixLocalization.Inventory.List.SIPURI).Filterable(false);
})
.Sortable()
.Filterable()
.Events(e => e.FilterMenuInit("initCheckboxFilter"))
.DataSource(dataSource => dataSource
.WebApi()
.Model(model =>
{
model.Id(inventoryList => inventoryList.Id); // Specify the property which is the unique identifier of the model
model.Field(inventoryList => inventoryList.Id).Editable(false); // Make the ProductID property not editable
})
.Create(create => create.Url(Url.HttpRouteUrl("DefaultApi", new { controller = "EndpointKds" }))) // Action invoked when the user saves a new data item
.Read(read => read.Url(Url.HttpRouteUrl("DefaultApi", new { controller = "EndpointKds" }))) // Action invoked when the grid needs data
)
.Pageable()
)
I am not sure what could be causing the described problem and at least when I tested with the example, the filtering was working correctly for multiple fields. Could you check this updated version and let me know if I am missing something?
Regards,
Daniel
Telerik
It seems when I set ServerOperation to false, this fixes it, however for our situation we need to have this set as True as we only want to send back data that is in the page view and not all data.
First off this is great. It works as expected if filtering on that column alone
I have issues when it comes to multi-column sorting. If I sort by column A then by the StatusEnum column I can see that the Ajax grid is posting two times, first with the correct filters (Column A, and column StatusEnum) and gets a valid result. but then immediately does another ajax call only with column A filters?
The same thing happens if I pre-filter "statusEnum":
.Filter(filter => filter.Add(p => p.StatusEnum).IsNotEqualTo(Enums.StatusEnums.Cancelled)
It initials loads with only cancled, then if I change the filter it does two ajax calls, first what my new selection is, second the original filter.
Here is the filter js:
function onFilterMenuInit(e) {
if (e.field == "StatusEnum") {
initCheckboxFilter.call(this, e);
}
}
function initCheckboxFilter(e) {
var grid = $("#Tasks").data("kendoGrid");
var field = e.field;
var checkboxesDataSource = new kendo.data.DataSource({
data: [
{ Label: "Not Started", Enum: 0 },
{ Label: "On Hold", Enum: 1 },
{ Label: "Complete", Enum: 2 }
]
});
var helpTextElement = e.container.children(":first").children(":first");
helpTextElement.nextUntil(":has(.k-button)").remove();
var element = $("<div class='checkbox-container'></div>").insertAfter(helpTextElement).kendoListView({
dataSource: checkboxesDataSource,
template: "<div><label><input type='checkbox' value='#:Enum#'/> #:Label#</label></div>"
});
e.container.find("[type='submit']").click(function (e) {
var filter = grid.dataSource.filter() || { logic: "and", filters: [] };
var fieldFilters = element.find(":checkbox:checked").map(function (idx, input) {
return {
field: field,
operator: "eq",
value: input.value
};
});
if (fieldFilters.length) {
removeFiltersForField(filter, field);
filter.filters.push({
logic: "or",
filters: fieldFilters
});
grid.dataSource.filter(filter);
}
});
}
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;
}
});
}
}
I have issues when it comes to multi-column filtering. If I filter by column
Thien
If server operations are enabled then the dataSource will have the data only for the current page and filters so if all items should be shown in the checkboxlist then you should make a separate request to get all items. The filter should still work as expected for multiple columns. I attached a sample MVC project which uses server operations and seems to work as expected. Let me know if I am missing something.
Chris
I couldn't reproduce the multiple requests. Could you provide a runnable sample?
Regards,
Daniel
Telerik
I believe you are having the same issue that I am having however its just being masked by the data. As a quick replication :-
Select a filter on Endpoint Model Name as 3 4 and 5
Then on Software Version Type Name select 4
This correctly filters to just one item (item 4) however if you remove the item 4 filter we should then have items 3,4,5 appear since they were added as filters, unfortunately however they revert to the full dataset.
The problem I am seeing is that when you have two filters set and ServerOperation is true the DataSource does not return the list of filters and only applies the most recent filter instead of all filters.
Thanks
Thien
Thank you for pointing out the issue. It seems that the default filter menu submit handler will still clear the filters for the field if there are not any values in the expected inputs. I attached an updated version of the project that stops the default handler and manually closes the popup which should resolve the problem.
Regards,
Daniel
Telerik
Thanks for this fix. We also found a fix by adding a return false at the end of Submit button handler event.
Do you know how I can make it auto do this for any enum? Currently if I have an enum the telerik grid makes filters that are a dropdown of the enum options. I would like any enum to automatically make this check box filter option, giving a check box for each possible enum.
The grid treats enumerations the same way as foreignkey fields so you could check if the grid column has a values option in order to automatically initialize a checkbox filter in this scenario e.g.
function
onFilterMenuInit(e) {
var
field = e.field;
var
columns =
this
.columns;
var
column;
for
(
var
idx = 0; idx < columns.length; idx++) {
if
(columns[idx].field == field) {
column = columns[idx];
break
;
}
}
if
(column.values) {
//init checkbox filter
}
}
Regards,
Daniel
Telerik
I have faced the same problem that Thein has faced like the following,
I need to reset the checkboxes in case the user changes their selections but then never clicks on the filter or clear button and just closes the menu.
I am not sure how we can reset the user changed checkboxes unless user clicks the Fliter or Clear button. Is it possible to do with the close event as described,
function
initCheckboxFilter(e) {
e.container.data(
"kendoPopup"
).bind(
"close"
,
function
(e) {
//your logic
});
I have fixed the Issue: Reset the checkboxes in case the user changes their selections but then never clicks on the filter or clear button and just closes the menu.
Telerik Example: http://dojo.telerik.com/IWudI
I have taken the code example from the above telerik link & modified the following,
function
initCheckboxFilter(e) {
var
popup = e.container.data(
"kendoPopup"
);
var
dataSource =
this
.dataSource;
var
field = e.field;
var
checkboxesDataSource =
new
kendo.data.DataSource({
data: uniqueForField(dataSource.data(), field)
});
e.container.data(
"kendoPopup"
).bind(
"close"
,
function
(e) {
checkboxesDataSource.data(uniqueForField(dataSource.data(),field));
var
appliedFilter = dataSource.filter();
if
(appliedFilter !=
null
&& appliedFilter != undefined) {
for
(i = 0; i < appliedFilter.filters.length; i++) {
var
appliedFiltersChild = appliedFilter.filters[i];
for
(j = 0; j < appliedFiltersChild.filters.length; j++) {
if
(appliedFiltersChild.filters[j].field == field)
$(
"div[class='k-animation-container'] input[type='checkbox'][value='"
+ appliedFiltersChild.filters[j].value +
"']"
).prop(
'checked'
,
true
);
}
}
} });
}
I have fixed the Issue: Reset the checkboxes in case the user changes their selections but then never clicks on the filter or clear button and just closes the menu.
Telerik Example: http://dojo.telerik.com/IWudI
I have taken the code example from the above telerik link & modified the following,
function
initCheckboxFilter(e) {
var
popup = e.container.data(
"kendoPopup"
);
var
dataSource =
this
.dataSource;
var
field = e.field;
var
checkboxesDataSource =
new
kendo.data.DataSource({
data: uniqueForField(dataSource.data(), field)
});
e.container.data(
"kendoPopup"
).bind(
"close"
,
function
(e) {
checkboxesDataSource.data(uniqueForField(dataSource.data(),field));
var
appliedFilter = dataSource.filter();
if
(appliedFilter !=
null
&& appliedFilter != undefined) {
for
(i = 0; i < appliedFilter.filters.length; i++) {
var
appliedFiltersChild = appliedFilter.filters[i];
for
(j = 0; j < appliedFiltersChild.filters.length; j++) {
if
(appliedFiltersChild.filters[j].field == field)
$(
"div[class='k-animation-container'] input[type='checkbox'][value='"
+ appliedFiltersChild.filters[j].value +
"']"
).prop(
'checked'
,
true
);
}
}
} });
}
Hi,
Would it be possible to make the multi-checkbox filter checked by default, i.e. similar to what excel does?
You can apply the initial state in the template:
template:
"<div><input type='checkbox' checked='checked' value='#:"
+ field +
"#'/>#:"
+ field +
"#</div>"
Regards,
Daniel
Telerik
Hi Daniel,
I am trying to create a multi checkbox filter for a Kendo grid column. For this feature I am using "multi:true" property on the column's filterable. I also want to use the "ui" callback function (filterable:ui) which does not seem to work when I have the "multi:true" property set. If I remove this property, the "ui:function(e){}" gets called.
Is there a way I can use both these together? - https://dojo.telerik.com/EcUdaFeT/5
Generally the filterable.ui setting is used when customizing the filter for a given Grid column. For example when you would like to use a different input in the filter menu.
With that said, would you elaborate in more detail what is the functionality you would like to implement? If we have better understanding of your goal we will be able to provide specific suggestions on how it can be implemented.
Regards,
Viktor Tachev
Progress Telerik
Hi Daniel.
I how can I achieve this when I have column menu specified on the grid?
I've found this post (https://www.telerik.com/forums/filtermenuinit-event-not-fired) that says to use columnMenuInit instead. But when I do so, I don't seem to have the same access to the Filter Container as your example demonstrates?
Hello Shawn,
When you specify filterable.ui for a Grid column the customized filter will be used with filter menu and column menu. There is no need to handle other events in this case. Check out the example below that illustrates how you can customize the filters when column menu is enabled.
https://dojo.telerik.com/aNAWEnev
Regards,
Viktor Tachev
Progress Telerik
Hi Len,
I guess that you are addressing the checboxes shown in the column menu in the previous example.
When the column menu is opened the internal logic that is responsible for showing it considers what columns are visible and shows the respective checkboxes as checked.
In case you have something else in mind please elaborate in more detail on what it is.
Regards,
Viktor Tachev
Progress Telerik
Five days of Blazor, Angular, React, and Xamarin experts live-coding on twitch.tv/CodeItLive , special prizes and more, for FREE?! Register now for DevReach 2.0(20).