MultiSelect Binding to Collection with Count 1 , when selection is empty

9 posts, 1 answers
  1. Ralf
    Ralf avatar
    5 posts
    Member since:
    Aug 2016

    Posted 18 Apr Link to this post

    I have a view model 'OrderViewModel' with a property

    public ICollection<Person> Team { get; set; }

    I use a Kendo Grid element to display a list of the 'OrderViewModel' Objects and use a Popup with a template to edit the data.

    In my razor view if the edit view i use a multiSelect Element to edit the 'Team' property

    @(Html.Kendo().MultiSelect()
                       .Name("Team")
                       .DataTextField(field: "FullName")
                       .DataValueField(field: "Id")
                       .AutoBind(autoBind: false)
                       .DataSource(s => s.Read(read => read.Action(actionName: "TeamMemberRead", controllerName: "Grid")).ServerFiltering(enabled: true))
           )

    When the data is posted back to the controller and nothing is selected in the multiselect field, the value for the 'Team' property is a List with Count = 1 and the element [0] is null.

    Is this the correct behavior? I expect a list with Count = 0.

    Here is my controller action:

    [HttpPost]
            public ActionResult Orders_Update([DataSourceRequest]DataSourceRequest request, OrderViewModel data)
            {
                if (data != null && ModelState.IsValid)
                {
                    // Update
                    int count = data.Team.Count;
                }
     
                return Json(new[] { data }.ToDataSourceResult(request, ModelState));
            }

     

  2. Ianko
    Admin
    Ianko avatar
    1741 posts

    Posted 19 Apr Link to this post

    Hello Ralf,

    On my end implementing a similar scenario, the Team field is null in such a situation. Here you are a screencast (https://www.screencast.com/t/yIY61aRD) that shows the output I receive by further updating this example here: https://github.com/telerik/ui-for-aspnet-mvc-examples/tree/master/grid/custom-popup-editor

    If you still have issues with the matter you can attach a simple, locally runnable project which to investigate further and see why do you receive different output. 

    Regards,
    Ianko
    Telerik by Progress
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  3. Ralf
    Ralf avatar
    5 posts
    Member since:
    Aug 2016

    Posted 19 Apr in reply to Ianko Link to this post

    Hello Ianko,

    Thank you for your reply.

    I attached you my test project for this, because the other project with this problem is to big. If you set a break point in the method "Orders_Update" of the "GridController", you could see the data send to the server.

    If you edit the field above "Team" of row "Order ID = 1", you will see, you get a collection with one null element back.

    If you remove the person entry in "Team" of row "Order ID = 15", you will see, you get a property "Team" with value null (No Collection). If you edit this row again (without leaving the grid) and fill a value in the field above "Team" without selecting a person, you will get a collection with one null element back.

    Maybe you get the same result in your example, if edit the row a second time, after you removed the person from Team.

    Thank you for your help,

    Ralf

     

  4. Ianko
    Admin
    Ianko avatar
    1741 posts

    Posted 20 Apr Link to this post

    Hello Ralf,

    I tested the project sent, but no matter how items are removed and how the field is edited I am unable to get a collection with one null item. It either returns a collection with all items or null. Here you are a recording of the results on my end: https://www.screencast.com/t/ym4oz7cRXFg. If the steps I follow are different, please record a screencast of your own to show me the exact behavior. 

    Regards,
    Ianko
    Telerik by Progress
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  5. Ralf
    Ralf avatar
    5 posts
    Member since:
    Aug 2016

    Posted 20 Apr Link to this post

    Hello Ianko,

    Thank you for your test. I am not able to send you a screencast. But I send you a new project (I improved the popup edit form) and in the zip-File "2017_04_17_telerik_problem.zip" there is a pdf-File with some screenschots and a description how I get this behavior. I hope this help you to reproduce my problem.

    Regards, Ralf

  6. Ianko
    Admin
    Ianko avatar
    1741 posts

    Posted 21 Apr Link to this post

    Hello Ralf,

    Can you please remove custom build steps, code, and configuration that is not related to the issue with the MultiSelect component?

    Regards,
    Ianko
    Telerik by Progress
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  7. Ralf
    Ralf avatar
    5 posts
    Member since:
    Aug 2016

    Posted 21 Apr Link to this post

    Hello Ianko,

    there are no custom build steps in the solution.

    I created a standard "Telerik ASP.NET MVC Application" with "Grid and Menu"

    After this I only edit the GridController and the layout view and  add the Person class and the views for the popup edit.

    I did not change build steps and so on.

    I have attached a zip-file, with the files I have added or changed. So maybe you could create your own Telerik Solution and replace the files with the versions from my zip-File.

    Regards,

    Ralf

  8. Answer
    Ianko
    Admin
    Ianko avatar
    1741 posts

    Posted 24 Apr Link to this post

    Hello Ralf,

     

    I am not sure then why Visual Studio refuses to open the project.

     

    However, I was able to recreate with the resources from your last message. The described behavior is actually a .NET object serialization matter, which seems rather expected. 

     

    This first you can investigate is the Network requests, where you can see the Team field sent as null. But .NET serializes this to a list with one null object as the expected object for this case is a List, which is a correct behavior as the bound data is null and not an empty list. 

     

    Next, modifying the item with the already defined Team field to null works. Because the MVVM binding behind will process data properly and sent an array with no items. Which in .NET is serialized to null. 

     

    If you change the read action so that empty lists are bound you will have the proper behavior initially.

     

    ...
     
    List<OrderViewModel> result = Enumerable.Range(1, 10).Select(i => new OrderViewModel
    {
        OrderID = i,
        Freight = i * 10,
        ShipName = "ShipName " + i,
        ShipCity = "ShipCity " + i,
        Team = new List<Person>()
    }).ToList();
     
    ...

    In order for that to work you should always assure that an empty list is bound. 

    You can also try if using a foreign column would be more appropriate for the case: http://demos.telerik.com/aspnet-mvc/grid/foreignkeycolumn. 

    Or, finally, you can handle the change event of the DataSource in order to correct the item update by changing the null item to an empty list, which on the server will be resolved as null. 

    @(Html.Kendo().Grid<TelerikMvcApp1.Models.OrderViewModel>()
                    .Name("grid")
                    .Columns(columns =>
                    {
                        columns.Command(command => command.Edit());
                        columns.Bound(p => p.OrderID).Filterable(false);
                        columns.Bound(p => p.Freight);
                        columns.Bound(p => p.ShipName);
                        columns.Bound(p => p.ShipCity);
                        //columns.Bound(p => p.TeamNames);
                    })
                    .Editable(e => e.Mode(GridEditMode.PopUp)
                        .TemplateName("EditOrderView").Window(w => w.Width(500))
                    )
                    .Pageable()
                    .Sortable()
                    .Scrollable()
                    .Filterable()
                    .HtmlAttributes(new { style = "height:550px;" })
                    .DataSource(dataSource => dataSource
                        .Ajax()
                        .PageSize(20)
                        .Events(events => events.Error(handler: "onErrorTest").Change("onChange"))
                        .Read(read => read.Action("Orders_Read", "Grid"))
                        .Update(u => u.Action("Orders_Update", "Grid"))
                        .Model(model =>
                        {
                            model.Id(d => d.OrderID);
                             
                        }
                         
                         
                        )
                    )
                )
            </div>
        </div>
    </div>
     
    <div>
        @Html.ActionLink("Edit Test", "EditTest", "Grid")
    </div>
    <script>
        function onErrorTest(args) {
            alert('Fehler');
        }
     
        function onChange(e) {
            if (e.action === "itemchange")
            {
                if (e.items[0] && !e.items[0].Team) {
                    e.items[0].set("Team", []);
                }
            }
        }
    </script>

    Regards,
    Ianko
    Telerik by Progress
    Try our brand new, jQuery-free Angular 2 components built from ground-up which deliver the business app essential building blocks - a grid component, data visualization (charts) and form elements.
  9. Ralf
    Ralf avatar
    5 posts
    Member since:
    Aug 2016

    Posted 25 Apr in reply to Ianko Link to this post

    Hello Ianko,

    thank you very much for your help. I find a solution with your tips now.

    I extended the constructor from "OrderViewModel". 

    public OrderViewModel()
            {
                Team = new List<Person>();
            }

    This has the effect, that in the update function, the Team property is not null, if an array with no items is sent.

    And so when the data is sent back to the browser the Team property is not null.

    Regards,

    Ralf

Back to Top