I have a column inside a grid that is bind to DevelopersDataSource this is object that contains only id and name.
But the filter doesn't work and fell exception then if I change to simple string then the edit doesn't work properly.
so what can I do?
this is my grid:
<script type="text/kendo" id="DevelopersTemplate">
<ul>
#for(var i = 0; i< data.length; i++){#
<li title="#:data[i].Name#">#:data[i].Name#</li>
#}#
</ul>
</script>
@Html.Partial("~/Views/Shared/Info.cshtml", Model)
@(Html.Kendo().Grid<TaskViewModel>()
.Name("GridTasks")
.Columns(columns =>
{
columns.Bound(c => c.ID).Hidden();
columns.Bound(c => c.ProjectID).Title("Project Id").Hidden();
columns.Bound(c => c.ProjectName).Title("Project Name").Hidden();
columns.Bound(c => c.Name).Title("Name");
columns.Bound(c=>c.DevelopersDataSource).ClientTemplate("#=DevelopersTemplate(DevelopersDataSource)#").EditorTemplateName("DevelopersEditor").Title("Developers").Sortable(false).Filterable(f => f.UI("developersMultiFilter")
.Mode(GridFilterMode.Row)
.Extra(false)
.Operators(operators => operators
.ForString(str => str.Clear()
.IsEqualTo("contains"))));
columns.Bound(c => c.ActualStartDate).Title("Actual Start Date").EditorTemplateName("ActualStartDateEditor").Format("{0: MM/dd/yyyy}");
columns.Bound(c => c.ActualEndDate).Title("Actual End Date").EditorTemplateName("ActualEndDateEditor").Format("{0: MM/dd/yyyy}");
columns.Bound(c => c.EstimatedStartDate).Title("Estimated Start Date").EditorTemplateName("EstimatedStartDateEditor").Format("{0: MM/dd/yyyy}");
columns.Bound(c => c.EstimatedEndDate).Title("Estimated End Date").EditorTemplateName("EstimatedEndDateEditor").Format("{0: MM/dd/yyyy}");
columns.Bound(c => c.PercentCompleted).Title("Percent Completed").Width(130).ClientTemplate("<canvas id='taskChart_#=ID #' width='94' height='94' style='display: block; width: 94px; height: 94px;'></canvas>").EditorTemplateName("PercentCompletedEditor");
;
columns.Bound(c => c.Comment).Title("Comment");
columns.Command(command => { command.Edit(); command.Destroy(); }).Width(250);
})
.Scrollable()
.Resizable(resize => resize.Columns(true))
.Editable(editable => editable.Mode(GridEditMode.InLine).TemplateName("TaskEdit"))
.Groupable(g => g.Enabled(false))
.Filterable()
.ToolBar(toolbar =>
{
toolbar.Template(@<text>
<div class="toolbar" style="float:left">
<a class="k-button k-button-icontext" onclick='addTaskAjax()' href="#">
<span class="k-icon k-i-add"></span> ADD TASK
</a>
<a class="k-button k-grid-excel k-button-icontext" href="#">
<span class="k-icon k-i-excel"></span>Export to Excel
</a>
</div>
</text>);
})
.Excel(excel => excel
.AllPages(true)
.FileName("Tasks.xlsx")
.Filterable(true)
.ForceProxy(true)
.ProxyURL(Url.Action("FileExportSave", "Home")))
.Pageable(pager => pager
.Refresh(true)
.PageSizes(true)
.PageSizes(new int[] { 6, 15, 20 })
.ButtonCount(5))
.Sortable(sortable =>
{
sortable.SortMode(GridSortMode.MultipleColumn)
.Enabled(true);
})
.Events(events => events.DataBound("onDataBoundSavedTasks").Cancel("createPieAfterCancellation"))
.DataSource(dataSource => dataSource
.Ajax()
.ServerOperation(false)
.Group(group => group.Add(p => p.ProjectName))
.PageSize(20)
.Events(events => events.Error("errorHandlerTask"))
.Read(read => read.Action("GetSavedTasks", "Task"))
.Update(update => update.Action("UpdateTask", "Task"))
.Destroy(update => update.Action("DeleteTask", "Task"))
.Model(model => model.Id(item => item.ID))))
this is my mode:
namespace TaskManagementUI.Models
{
public class TaskViewModel
{
public TaskViewModel()
{
DevelopersDataSource=new List<Developer>();
}
public int? ID { get; set; }
[Display(Name = "Project Name")]
public int ProjectID { get; set; }
[Display(Name = "Name")]
[Required(ErrorMessage = "Please enter task name")]
public string Name { get; set; }
[Display(Name = "Project Name")]
public string ProjectName { get; set; }
[Required(ErrorMessage = "Please select a developer")]
[Display(Name = "Developers")]
public List<int> DevelopersID { get; set; }
[DataType(DataType.Date)]
[Required(ErrorMessage = "Please select a date")]
[Display(Name = "Estimated Start Date")]
public DateTime EstimatedStartDate { get; set; }
[GreaterDate(EarlierDateField = "EstimatedStartDate", ErrorMessage = "End date should be after Start date")]
[DataType(DataType.Date)]
[Required(ErrorMessage = "Please select a date")]
[Display(Name = "Estimated End Date")]
public DateTime EstimatedEndDate { get; set; }
[DataType(DataType.Date)]
[Required(ErrorMessage = "Please select a date")]
[Display(Name = "Actual Start Date")]
public DateTime ActualStartDate { get; set; }
[GreaterDate(EarlierDateField = "ActualStartDate", ErrorMessage = "End date should be after Start date")]
[DataType(DataType.Date)]
[Required(ErrorMessage = "Please select a date")]
[Display(Name = "Actual End Date")]
public DateTime ActualEndDate { get; set; }
[UIHint("PercentCompletedEditor")]
[Required(ErrorMessage = "Please enter percent")]
[Display(Name = "Percent Completed")]
public float PercentCompleted { get; set; }
[Required(ErrorMessage = "Please enter comment")]
[Display(Name = "Comment")]
public string Comment { get; set; }
[Required(ErrorMessage = "Please select a developer")]
[UIHint("DevelopersEditor")]
public List<Developer> DevelopersDataSource { get; set; }
public string DevelopersNames
{
get
{
if(DevelopersDataSource!=null)
return String.Join(",", DevelopersDataSource.Select(s=>s.Name));
else
{
return null;
}
}
}
public List<Project> Projects { get; set; }
}
}
this is the object developer:
namespace TaskManagementUI.Models
{
public class Developer
{
public int? ID { get; set; }
[Required(ErrorMessage = "Please enter a name")]
[Display(Name = "Name")]
public string Name { get; set; }
}
}
this is my filter function to DevelopersDataSource :
var developersMultiFilter = function (element) {
element.kendoMultiSelect({
dataValueField:"ID",
dataTextField:"Name",
dataSource: {
transport: {
read: "/Project/DevelopersList"
},
valuePrimitive: false
},
});
}
thanks
23 Answers, 1 is accepted
Thank you for the provided information.
The described result is expected because if the Column is bound to a complex object the filtering(sorting) cannot automatically determine which field from the object has to be used for these operations.
More details and suggestions can be found at the following forum:
https://www.telerik.com/forums/sorting-and-filtering-for-custom-object-in-column-doesn%27t-work
Regards,
Stefan
Progress Telerik
yes, I know it but when I bound the column to field that contains only names , the editor doesn't work on this column,
I work for this hours.
the link that you gave me is not for list and that example I did by my self
someone can help me with a detailed explanation.
thanks
In this scenario, I can recommend the suggested in the forum approach with ForeignKey column. This will show the desired DropDown editor and it will allow using the built-in filter.
This can be observed in our demo:
http://demos.telerik.com/aspnet-mvc/grid/foreignkeycolumn
This is also the relevant code used for populating the categories:
private
void
PopulateCategories()
{
var dataContext =
new
SampleEntities();
var categories = dataContext.Categories
.Select(c =>
new
CategoryViewModel {
CategoryID = c.CategoryID,
CategoryName = c.CategoryName
})
.OrderBy(e => e.CategoryName);
ViewData[
"categories"
] = categories;
ViewData[
"defaultCategory"
] = categories.First();
}
Regards,
Stefan
Progress Telerik
but I need to present a list not to choose only one.
for this I need multi select and this is not the same
Indeed, this will allow only a single selection.
The following forum contains an example on how to make a filter for List of strings:
https://www.telerik.com/forums/filtering-by-list-string-#-lAocEgVdESPrSaquRC_oQ
I hope this will help by providing guidance in the right direction.
If additional assistance is needed, please provide a fully runnable example, so we can make suggestions best suited for the real scenario.
Regards,
Stefan
Progress Telerik
thanks,
is it any way to the same in the row of the filter?
A similar approach could be used inside the filter.UI option but it will require some changes:
1) Set the following MultiSelect and its change event:
function developersMultiFilter(element) {
element.kendoMultiSelect({
dataValueField: "TerritoryID",
change: function (e) {
var grid = $("#grid").data("kendoGrid"),
value = this.value();
filterData = {};
serializeArray("territories", value, filterData);
},
dataTextField: "TerritoryDescription",
dataSource: {
data: [{ "TerritoryID": "06897", "TerritoryDescription": "Wilton" }, { "TerritoryID": "19713", "TerritoryDescription": "Neward" }] //Load the desired data
}
});
}
2) Then as the Grid will send the actual filter again as it is part of the Grid filter UI, reset it in the Controller to only use the custom filter:
public
ActionResult Read([DataSourceRequest] DataSourceRequest request, IEnumerable<
string
> territories)
{
IEnumerable<EmployeeViewModel> employees = repository.Employees;
if
(territories !=
null
)
{
employees = employees.Where(e => e.Territories.Any(t => territories.Contains(t.TerritoryID)));
}
request.Filters =
new
List<Kendo.Mvc.IFilterDescriptor>();
return
Json(employees.ToDataSourceResult(request));
}
Regards,
Stefan
Progress Telerik
thank you very much,
it's really good, but the clear button it's not working at all.
why?
Regarding the questions:
1) This occurs because the Grid build-in filtering is not used, and the filters have to be cleared programmatically. I can suggest on the filterMenuInit to subscribe the to cleat button, and then before sending the filter data to the controller to set clear to "filterData" variable depending on the clear button click:
https://docs.telerik.com/kendo-ui/api/javascript/ui/grid#events-filterMenuInit
var
clear =
false
;
function
onFilterMenuInit(e) {
$(e.container).find(
'[type="reset"]'
).click(
function
(e) {
clear =
true
;
})
}
function
additionalData(e) {
if
(clear) {
filterData = {}
clear =
false
;
}
return
filterData;
}
2) As the value will be populated only if the built-in filter is used, the values have to be populated manually when the filter form is opened:
https://docs.telerik.com/kendo-ui/api/javascript/ui/grid#events-filterMenuOpen
function
onFilterMenuOpen(e) {
var
multiselect = $(e.container).find(
'[data-role="multiselect"]'
).data(
'kendoMultiSelect'
);
multiselect.value(MultiSelectValue)
}
function
developersMultiFilter(element) {
console.log(filterData)
element.kendoMultiSelect({
dataValueField:
"TerritoryID"
,
change:
function
(e) {
var
grid = $(
"#grid"
).data(
"kendoGrid"
),
value =
this
.value();
MultiSelectValue =
this
.value();
// get the current value, so it can be set when the filter is opened again
filterData = {};
serializeArray(
"territories"
, value, filterData);
},
Please have in mind that additional modifications can be needed, due to the manual approach used for filtering, for example to Grid filter has to be taken into account when it is applied to the other columns.
Regards,
Stefan
Progress Telerik
thank you very much!!
the clear button is working perfect!
about the multi select values:
(1 how do I bind FilterMenuOpen event to the grid in mvc (I don't find any event like that)?
(2 who is MultiSelectValue, where you declare it and what the value you initialized it?
thanks
There should be an event called FilterMenuOpen:
https://docs.telerik.com/kendo-ui/api/javascript/ui/grid#events-filterMenuOpen
Please have in mind that this is a relatively new event and it may not be available in the older versions of the widget.
Regards,
Stefan
Progress Telerik
Ok thanks
can you tell me exactly which version is it?
I use 2017.1,504
The filterMenuOpen event was introduced in the Kendo UI R2 2017 (2017.2.504) release.
Having said that, it should be available for your project.
Do not hesitate to write back if you have any further questions.
Regards,
Preslav
Progress Telerik
this is the version I have, but this event does not appear when I open the events list, maybe can I bind it in another way?
(in 2017.3.1026 it appears, i tried it in trial version)
thanks
I found an issue that states that the filterMenuOpen event was not added to the MVC wrappers with the Kendo UI R2 2017 release. It was fixed with the Kendo UI R3 2017.
To overcome this, I would suggest using one of the following workarounds:
- Bind to the event with JavaScript(the jQuery way). For example, the code could look like:
<script>
$(document).ready(
function
() {
var
grid = $(
"#myGridID"
).data(
"kendoGrid"
);
grid.bind(
"filterMenuOpen"
, grid_filterMenuOpen);
});
function
grid_filterMenuOpen(e) {
console.log(
"grid_filterMenuOpen"
);
}
</script>
- Update the Kendo UI version to the latest.
I hope the above workarounds work for you.
Regards,
Preslav
Progress Telerik
Hi,
about this function:
additionalData(e) {
if (clear) {
filterData = {}
clear = false;
}
return filterData;
}
I don't want to clear the filterData in clear that was done in other filed filter.
How can I find from which column the clear came.
thanks
To remove a single property of the filterData object, use the delete action. For example, check this forum:
Do not hesitate to write back if you have any further question.
Regards,
Preslav
Progress Telerik
I really don't understand why this information helps me???
in every time I do filter the clear equals to true or false, and I don't know from which field the "clear" is coming.
How can I find from which column the clear came??
thanks
sorry,
I solve it.
Thanks