Reputation: 4359
I have created a ViewModel with two things, a Contact and a list of Phones for that Contact.
My goal is to add data for a new Contact, and add a few Phones, and then save by a Controller action.
I've edited the scaffolded Create.cshtml for my Contact, added a grid for the phones. Added a javascript for creating the phones. So far so good.
The problem is when I click the Create button, and I get back to the Controller, I get no Phones. How do I (in the View) add the phone-rows to my IEnumerable?
EDIT: Took out code in view that was not correct in this context.
My ViewModel:
public class ContactViewModel
{
public Contact Contact {get; set;}
public IEnumerable<Phone> Phones { get; set; }
}
My view:
@model PilotKibsNet.Controllers.ContactViewModel
<script type="text/javascript" src="../../Scripts/jquery-1.5.1.js"></script>
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script type="text/javascript">
function Add() {
$("#tbl > tbody:last").append("<tr><td>" + $("#Number").val() + "</td><td>" + $("#Kind").val() + "</td><td></td></tr>");
$("#Number").val("");
$("#Kind").val("");
}
</script>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Contact</legend>
<div class="editor-label">
@Html.LabelFor(model => model.Contact.Name)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Contact.Name)
@Html.ValidationMessageFor(model => model.Contact.Name)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Contact.Address)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Contact.Address)
@Html.ValidationMessageFor(model => model.Contact.Address)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Contact.City)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Contact.City)
@Html.ValidationMessageFor(model => model.Contact.City)
</div>
<legend>Phone numbers</legend>
<label>Number :</label>
@Html.TextBox("Number")
<label>Kind :</label>
@Html.TextBox("Kind")
<input type="button" value="Add" onclick="Add()" />
<table id="tbl">
<tr>
<th>
Phone
</th>
<th>
Kind
</th>
<th></th>
</tr>
<tbody>
</tbody>
</table>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
And then, in by Controller action, the Contact has the data, but the Phone is an empty list.
[HttpPost]
public ActionResult Create(ContactViewModel contactViewModel)
{
if (ModelState.IsValid)
{
contactViewModel.Contact.id = Guid.NewGuid();
db.Contacts.AddObject(contactViewModel.Contact);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(contactViewModel.Contact);
}
How do I get the Phones back to the server?!?
Upvotes: 1
Views: 3358
Reputation: 1038710
You have only display templates for those Phones collection. No value at all will be sent to the server. You could use hidden fields if the user is not supposed to edit the values or textboxes if he is.
Also I would replace this foreach loop in your view by an editor template:
if (Model != null)
{
@Html.EditorFor(x => x.Phones)
}
and then I will define an editor template which would be rendered for each element of the Phones collection (~/Views/Shared/EditorTemplates/Phone.cshtml
):
@model Phone
<tr>
<td>
@Html.DisplayFor(x => x.Number)
@Html.HiddenFor(x => x.Number)
</td>
<td>
@Html.DisplayFor(x => x.Type)
@Html.HiddenFor(x => x.Type)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { id = Model.id }) |
@Html.ActionLink("Details", "Details", new { id = Model.id }) |
@Html.ActionLink("Delete", "Delete", new { id = Model.id })
</td>
</tr>
I have used hidden fields here to persist the values of the model so that when you post the form to the server they would be sent.
Another and IMHO better approach if the user is not supposed to edit those values in the table is to simply refetch them in your POST action from your database.
Upvotes: 2