I was having problems updating child collections of my object ( Foreign key constraint, EF with collection of childobjects ) which was solved using this guide: http://www.codetuning.net/blog/post/Binding-Model-Graphs-with-ASPNETMVC.aspx
When cleaning up my code, I moved the collection editing to a partial view.
@Html.Partial("_AttendeeInformationFields", Model.CaptureAttendeeInformationFields)
The partial view looks like this
@model ICollection<EventModel.Models.AttendeeInformationField>
<table id="CaptureAttendeeInformationFields">
<tr>
<th>@Html.GetDisplayName(model => model.FirstOrDefault().Name)</th>
<th>@Html.GetDisplayName(model => model.FirstOrDefault().Required)</th>
<th>@Html.GetDisplayName(model => model.FirstOrDefault().FieldType)</th>
@*<th>@Html.GetDisplayName(model => model.FirstOrDefault().InputType)</th>*@
</tr>
@Html.EditorForModel()
</table>
@Html.LinkToAddNestedForm("Lägg till", "#CaptureAttendeeInformationFields", ".AttendeeInformationField", "CaptureAttendeeInformationFields", typeof(EventModel.Models.AttendeeInformationField))
@Html.ValidationMessageFor(model => model)
Then I have a EditorTemplate for AttendeeInformationField that looks like this
@model EventModel.Models.AttendeeInformationField
<tr class="AttendeeInformationField">
@using (Html.BeginCollectionItem("CaptureAttendeeInformationFields"))
{
<td>@Html.TextBoxFor(model => model.Name) @Html.HiddenFor(model => model.MagnetEventId) @Html.HiddenFor(model => model.Id)</td>
<td>@Html.CheckBoxFor(model => model.Required)</td>
<td>@Html.DropDownListFor(model => model.FieldType, new SelectList(Enum.GetValues(typeof(EventModel.Models.FieldType)), Model.FieldType))</td>
@*<td>@Html.TextBoxFor(model => model.InputType)</td>*@
}
</tr>
The BeginCollectionItem is from this guide: http://ivanz.com/2011/06/16/editing-variable-length-reorderable-collections-in-asp-net-mvc-part-1/ This helps me with two things 1. The index is no longer a sequential 0-based integer series, and I can reorder my items, as well as add/delete without worrying about breaking the sequence. 2. The partial seems to loose the context, and my controls get names like "[0].Required" where it should be "CaptureAttendeeInformationField[0].Required". The BeginCollectionItem takes care of this.
The current problem is that these fixes doesn't seem to be compatible. I suppose it might have something to do with this disclaimer in the first article:
within this implementation we assume that the index is an integer starting at 0
I'm hoping that someone can point me in the right direction. Adding items in this solution works.
Ugly solution I sure hope this is not the only way to do this, but for now I've solved the problem like this:
foreach (var attendeeInformationField in viewModel.AttendeeInformationFields)
{
var attendeeInformationFieldId = attendeeInformationField.Id;
var originalAttendeeInformationField = original.CaptureAttendeeInformationFields.FirstOrDefault(aif => aif.Id == attendeeInformationFieldId);
if (originalAttendeeInformationField==null)
{
original.CaptureAttendeeInformationFields.Add(attendeeInformationField);
}
else
{
if (originalAttendeeInformationField != attendeeInformationField)
{
originalAttendeeInformationField = attendeeInformationField;
originalAttendeeInformationField.FieldType = attendeeInformationField.FieldType;
//originalAttendeeInformationField.InputType = attendeeInformationField.InputType;
originalAttendeeInformationField.Name = attendeeInformationField.Name;
originalAttendeeInformationField.Required = attendeeInformationField.Required;
}
}
}
I don't like it at all, but it works. There must be a better way of doing this.