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
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
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
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
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
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
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
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
>
Ianko
Telerik by Progress
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