I'm fairly new to MVC but am progressing. I have come across an issue that I can't seem to solve and would be greatful of any assistance.
When I post to the server my edits (in RoutineViewModel
) are mostly lost, primitive data types are persisted (in class Routine
) but collections of complex types (ICollection<RoutineExercise>)
are lost.
I found this MVC Form not able to post List of objects and followed the advice to seperate the view into an EditorTemplate but this has not worked. Using the '@foreach
' loop still produces all the page controls with the same id and name when you viewsource. I tried using a for (int i = 1; i <= 5; i++)
type loop as many other posts suggest but get errors about not being able to apply index to my object.
Also the fact this @Html.DropDownListFor(model => Model.ExerciseId, Model.Exercises, "", new { @class = "input-sm col-md-12" })
does not select the correct list item (Model.ExerciseId
has the correct value) concerns me.
Any help/advice would be great as I'm stuck and have been for 3 days now.
* POCO *
public partial class Routine
{
public Routine()
{
this.RoutineExercises = new List<RoutineExercise>();
}
public int Id { get; set; }
public string RoutineName { get; set; }
public string Description { get; set; }
...Other fields removed for clarity...
public virtual ICollection<RoutineExercise> RoutineExercises { get; set; }
}
public partial class RoutineExercise
{
public int Id { get; set; }
public int RoutineId { get; set; }
public int Exerciseid { get; set; }
public int SetsToDo { get; set; }
public int RepsToDo { get; set; }
...Other fields removed for clarity...
public virtual Exercise Exercise { get; set; }
public virtual Routine Routine { get; set; }
}
* VIEWMODEL *
public class RoutineViewModel
{
//Routine information
public int Id { get; set; }
[Display(Name = "Name")]
public string RoutineName { get; set; }
public string Description { get; set; }
//Exercise information
[Display(Name = "Exercise")]
public ICollection<RoutineExercise> RoutineExercises { get; set; }
public IEnumerable<SelectListItem> Exercises { get; set; }
public int ExerciseId { get; set; }
}
* FORM *
<div class="panel-body">
@using (Html.BeginForm("Edit", "Workout"))
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
@Html.ValidationSummary(true)
@Html.HiddenFor(model => model.Id)
@Html.EditorForModel()
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
</div>
* EDITOR TEMPLATE *
<div class="form-group">
@Html.LabelFor(model => model.RoutineName, new { @class = "control-label col-md-1" })
<div class="col-md-2">
@Html.EditorFor(model => model.RoutineName)
@Html.ValidationMessageFor(model => model.RoutineName)
</div>
@Html.LabelFor(model => model.Description, new { @class = "control-label col-md-1" })
<div class="col-md-2">
@Html.EditorFor(model => model.Description)
@Html.ValidationMessageFor(model => model.Description)
</div>
</div>
@foreach (var e in Model.RoutineExercises)
{
@Html.LabelFor(model => model.RoutineExercises, new { @class = "control-label col-md-1" })
<div class="col-md-3">
@*TO FIX This does NOT bind the selected value*@
@Html.DropDownListFor(model => Model.ExerciseId, Model.Exercises, "", new { @class = "input-sm col-md-12" })
</div>
<div class="col-md-12">
@Html.LabelFor(model => e.SetsToDo, new { @class = "control-label col-md-2" })
@Html.EditorFor(m => e.SetsToDo, new { @class = "control-label col-md-10" })
</div>
}
* CONTROLLER *
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(RoutineViewModel rvm) /*rvm always null for collections only*/
{
if (ModelState.IsValid)
{
//Save Routine
var r = new Routine
{
Id = rvm.Id,
RoutineName = rvm.RoutineName,
Description = rvm.Description,
RoutineFrequencyId = rvm.RoutineFrequencyId,
RoutineLengthId = rvm.RoutineLengthId
};
_repo.Update(r);
return RedirectToAction("Index");
}
return View(getRoutineViewModel(rvm.Id));
}