Edit 3 / Final
This is the fully working example using .NET MVC, Jquery and editor templates. https://www.dropbox.com/s/t4yxbhkuowyd7va/exerciseTest.rar
Edit 2
It finally works ! Thanks to the answer below. It appears that i needed to change the NewAnswerRow partial line:
<input type='text' id='Answers_@(Model.AnswerId)__Answer' name='Answers[@Model.AnswerId].Answer'/>
Thanks !
Edit 1:
I've followed this guide: http://www.techiesweb.net/asp-net-mvc3-dynamically-added-form-fields-model-binding/
The funny part is, that when I use his source, it works like it should. But it is almost exactly the same.
Original Post
First off all thanks for reading this message, and willing to help. I'm flabbergasted. Let me try to explain my situation. I'm trying to create a new exercise which has a list with answers. These answers are created on the fly with Jquery. I'm reading those answers with EditorTemplates. Everything works except that when i create new 'Answer' fields and press 'Post' My controller cant see any data (answers). The weird thing is. When I use data annotations like [required] in for example an answer property. I'm getting redirected to the Index. When I try it again, my model isn't empty anymore.
So basically my question is, how can i manage to get those answers into my list?
I've created a new project for you guys to be more clear and specific.
I have 2 models,
Exercise
Answers
ExerciseModel class
[Table("Exercise")]
public class ExerciseModel
{
[Key]
public int ExerciseId { get; set; }
public string Question { get; set; }
public IList<AnswerModel> Answers { get; set; }
}
It's basically a simple class. As you guys can see. There's a List with Answers.
AnswerModel
[Table("Answer")]
public class AnswerModel
{
[Key]
public int AnswerId { get; set; }
public string Answer { get; set; }
}
A simple AnswerModel class with an Id and an Answer.
My Controller
public class ExerciseController : Controller
{
private readonly DataContext db = new DataContext();
//
// GET: /Exercise/
public ActionResult Index()
{
var exercise = new ExerciseModel();
exercise.Answers = GetAnswers();
return View(exercise);
}
[HttpPost]
public ActionResult Index(ExerciseModel exercisemodel)
{
//need to implement interaction with database (not yet) testing phase.
return View("PostedData", exercisemodel);
}
public ActionResult NewAnswersRow(int id)
{
var answers = new AnswerModel { AnswerId = id };
return View("partial/NewAnswersRow", answers);
}
private List<AnswerModel> GetAnswers()
{
var answerslist = new List<AnswerModel>();
answerslist.Add(new AnswerModel { AnswerId = 1, Answer = "This is a hardcoded answer"}); //normally db.Answers (for testing purposes)
return answerslist;
}
}
My Index view
@model exerciseTest.Models.ExerciseModel
@using (Html.BeginForm())
{
<div class="divAnswers">
<div id="container">
<div class="editor-label">
@Html.LabelFor(model => model.Question)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Question)
@Html.ValidationMessageFor(model => model.Question)
</div>
@Html.EditorFor(m => m.Answers)
</div>
<input type="button" id="btnAdd" value="Add New Item" />
</div>
<p>
<input type="submit" value="Save" />
</p>
}
<script>
$(function () {
$("#btnAdd").click(function (e) {
var itemIndex = $("#container input.iHidden").length;
console.debug("itemIndex : "+itemIndex);
e.preventDefault();
$.get("@Url.Action("NewAnswersRow", "Exercise")/"+itemIndex,function(data){
$("#container").append(data);
});
});
});
</script>
My editor template of AnswerModel
@model exerciseTest.Models.AnswerModel
@{
Layout = null;
}
<script src="~/Scripts/jquery-1.7.1.min.js"></script>
<tr>
<td>
@Html.HiddenFor(x => x.AnswerId, new { @class="iHidden" })
@Html.TextBoxFor(x => x.Answer) </td>
</tr>
My NewAnswersRow.cshtml for creating new rows on the fly with Jquery (see Index for the code part)
@model exerciseTest.Models.AnswerModel
@{ Layout = null; }
<tr>
<td>
<input type="hidden" id="Answers_@(Model.AnswerId)__Id" class="iHidden" name='Answers[@Model.AnswerId].Id' />
<input type='text' id='Answers_@(Model.AnswerId)__AnswersText' name='Answers[@Model.AnswerId].AnswersText'/>
</td>
</tr>
And my 'postedData' view for testing purposes
@model exerciseTest.Models.ExerciseModel
<h3>Posted data is </h3>
@foreach (var item in Model.Answers)
{
<p>@item.Answer</p>
}
I'm trying to get this thing to work. I must say, In like 5 years, i've never asked someting here on StackOverflow because i could find answers. But this time, I need your help.
Thanks !
You have a bug in your NewAnswersRow partial view
. Name
and Id
are the same in your html, however it is name that is passed in a form post. If you look at what MVC
is doing, the name attribute of the answer text field is Answers[x].Answer
, while the Id
is Answers[x].AnswerText
.
So change your name='Answers[@Model.AnswerId].AnswerText'
to name='Answers[@Model.AnswerId].Answer'
so it matches what MVC
is expecting. Worked for me!