This is a migrated thread and some comments may be shown as answers.

Grid filter and edit

23 Answers 957 Views
Grid
This is a migrated thread and some comments may be shown as answers.
Michael
Top achievements
Rank 1
Michael asked on 22 Nov 2017, 08:58 AM

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

Sort by
0
Stefan
Telerik team
answered on 24 Nov 2017, 07:04 AM
Hello, Michael,

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
Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
0
Michael
Top achievements
Rank 1
answered on 26 Nov 2017, 08:21 AM

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

0
Stefan
Telerik team
answered on 28 Nov 2017, 08:34 AM
Hello, Michael,

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
Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
0
Michael
Top achievements
Rank 1
answered on 28 Nov 2017, 02:38 PM

but I need to present a list not to choose only one.

for this I need multi select and this is not the same

0
Stefan
Telerik team
answered on 30 Nov 2017, 08:19 AM
Hello, Michael,

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
Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
0
Michael
Top achievements
Rank 1
answered on 06 Dec 2017, 11:45 AM

thanks,

is it any way to the same in the row of the filter?

0
Stefan
Telerik team
answered on 07 Dec 2017, 01:55 PM
Hello, Michael,

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
Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
0
Michael
Top achievements
Rank 1
answered on 11 Dec 2017, 01:13 PM

thank you very much,

it's really good, but the clear button it's not working at all.

why?

0
Michael
Top achievements
Rank 1
answered on 12 Dec 2017, 11:42 AM
and also the the values in the multi select are invisible but stay there until new selection
0
Stefan
Telerik team
answered on 13 Dec 2017, 06:17 AM
Hello, Michael,

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
Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
0
Michael
Top achievements
Rank 1
answered on 13 Dec 2017, 09:43 AM

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

 

0
Michael
Top achievements
Rank 1
answered on 13 Dec 2017, 12:26 PM
sorry , 2 it's not a question, I  didn't pay attention
0
Stefan
Telerik team
answered on 15 Dec 2017, 07:42 AM
Hello, Michael,

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
Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
0
Michael
Top achievements
Rank 1
answered on 19 Dec 2017, 09:18 AM

Ok thanks

can you tell me exactly which version is it?

I use 2017.1,504

0
Michael
Top achievements
Rank 1
answered on 19 Dec 2017, 09:19 AM
sorry, 2017.2.504
0
Michael
Top achievements
Rank 1
answered on 19 Dec 2017, 09:20 AM
sorry 2017.2.504
0
Preslav
Telerik team
answered on 20 Dec 2017, 03:04 PM
Hi Michael,

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
Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
0
Michael
Top achievements
Rank 1
answered on 25 Dec 2017, 01:02 PM

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

0
Preslav
Telerik team
answered on 26 Dec 2017, 11:19 AM
Hello Michael,

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
Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
0
Michael
Top achievements
Rank 1
answered on 27 Feb 2018, 10:35 AM

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

 

0
Preslav
Telerik team
answered on 28 Feb 2018, 04:22 PM
Hello Michael,

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
Try our brand new, jQuery-free Angular components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
0
Michael
Top achievements
Rank 1
answered on 04 Mar 2018, 09:20 AM

 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

0
Michael
Top achievements
Rank 1
answered on 04 Mar 2018, 01:33 PM

sorry,

I solve it.

Thanks

Tags
Grid
Asked by
Michael
Top achievements
Rank 1
Answers by
Stefan
Telerik team
Michael
Top achievements
Rank 1
Preslav
Telerik team
Share this question
or