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

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

8 Answers 564 Views
MultiSelect
This is a migrated thread and some comments may be shown as answers.
Ralf
Top achievements
Rank 1
Ralf asked on 18 Apr 2017, 07:26 AM

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));
        }

 

8 Answers, 1 is accepted

Sort by
0
Ianko
Telerik team
answered on 19 Apr 2017, 10:53 AM

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.
0
Ralf
Top achievements
Rank 1
answered on 19 Apr 2017, 03:05 PM

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

 

0
Ianko
Telerik team
answered on 20 Apr 2017, 05:06 AM

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.
0
Ralf
Top achievements
Rank 1
answered on 20 Apr 2017, 07:24 AM

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

0
Ianko
Telerik team
answered on 21 Apr 2017, 05:48 AM

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.
0
Ralf
Top achievements
Rank 1
answered on 21 Apr 2017, 09:59 AM

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

0
Accepted
Ianko
Telerik team
answered on 24 Apr 2017, 10:54 AM

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 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 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.
0
Ralf
Top achievements
Rank 1
answered on 25 Apr 2017, 08:29 AM

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

Tags
MultiSelect
Asked by
Ralf
Top achievements
Rank 1
Answers by
Ianko
Telerik team
Ralf
Top achievements
Rank 1
Share this question
or