Grid filter and edit

14 posts, 0 answers
  1. Michael
    Michael avatar
    17 posts
    Member since:
    May 2014

    Posted 22 Nov Link to this post

    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

  2. Stefan
    Admin
    Stefan avatar
    1394 posts

    Posted 24 Nov Link to this post

    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.
  3. Michael
    Michael avatar
    17 posts
    Member since:
    May 2014

    Posted 26 Nov Link to this post

    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

  4. Stefan
    Admin
    Stefan avatar
    1394 posts

    Posted 28 Nov Link to this post

    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.
  5. Michael
    Michael avatar
    17 posts
    Member since:
    May 2014

    Posted 28 Nov Link to this post

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

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

  6. Stefan
    Admin
    Stefan avatar
    1394 posts

    Posted 30 Nov Link to this post

    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.
  7. Michael
    Michael avatar
    17 posts
    Member since:
    May 2014

    Posted 06 Dec Link to this post

    thanks,

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

  8. Stefan
    Admin
    Stefan avatar
    1394 posts

    Posted 07 Dec Link to this post

    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.
  9. Michael
    Michael avatar
    17 posts
    Member since:
    May 2014

    Posted 4 days and 23 hours ago Link to this post

    thank you very much,

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

    why?

  10. Michael
    Michael avatar
    17 posts
    Member since:
    May 2014

    Posted 4 days and 1 hour ago Link to this post

    and also the the values in the multi select are invisible but stay there until new selection
  11. Stefan
    Admin
    Stefan avatar
    1394 posts

    Posted 3 days and 6 hours ago Link to this post

    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.
  12. Michael
    Michael avatar
    17 posts
    Member since:
    May 2014

    Posted 3 days and 3 hours ago Link to this post

    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

     

  13. Michael
    Michael avatar
    17 posts
    Member since:
    May 2014

    Posted 3 days ago Link to this post

    sorry , 2 it's not a question, I  didn't pay attention
  14. Stefan
    Admin
    Stefan avatar
    1394 posts

    Posted 1 day and 5 hours ago Link to this post

    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.
Back to Top