I have an Asp.Net MVC 3 application with a database "Consultants", accessed by EF. Now, the Consultant table in the db has a one-to-many relationship to several other tables for CV type information (work experience, etc). So a user should be able to fill in their name etc once, but should be able to add a number of "work experiences", and so on.
But these foreign key tables are complex objects in the model, and when creating the Create View I only get the simple properties as editor fields. How do I go about designing the View or Views so that the complex objects can be filled in as well? I picture a View in my mind where the simple properties are simple fields, and then some sort of control where you can click "add work experience", and as many as needed would be added. But how would I do that and still utilize the model binding? In fact, I don't know how to go about it at all. (BTW, Program and Language stand for things like software experience in general, and natural language competence, not programming languages, in case you're wondering about the relationships there).
Any ideas greatly appreciated!
Here's the Create View created by the add View command by default:
@{
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>
@using (Html.BeginForm()) {
@Html.ValidationSummary(true)
<fieldset>
<legend>Consultant</legend>
<div class="editor-label">
@Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.FirstName)
@Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.LastName)
@Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.UserName)
@Html.ValidationMessageFor(model => model.UserName)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.Description)
@Html.ValidationMessageFor(model => model.Description)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
And here's the EF database diagram:
Update:
According to suggestion, I tried Steven Sanderson's blog solution, but I can't get it to work properly. I added this in the main view:
<div id="editorRows">
@foreach (var item in Model.Programs)
{
Html.RenderPartial("ProgramEditorRow", item);
}
</div>
<input type="button" value="Add program" id="addItem" />
I also added the javascript:
<script type="text/javascript">
var url = '@Url.Action("BlankEditorRow", "Consultant")';
$(document).ready(function () {
$("#addItem").click(function () {
$.ajax({
url: url,
cache: false,
success: function (html) {
alert(html);
$("#editorRows").append(html); }
});
return false;
});
});
</script>
A partial view:
@model Consultants.Models.Program
@using Consultants.Helpers
<div class="editorRow">
@*@using (Html.BeginCollectionItem("programs"))
{*@
@Html.TextBoxFor(model => model.Name)
@*}*@
</div>
And action methods in the controller:
public ActionResult Create()
{
Consultant consultant = new Consultant();
return View(consultant);
}
public ActionResult BlankEditorRow()
{
return PartialView("ProgramEditorRow", new Program());
}
Note that I commented out the Html.BeginCollectionItem part in the partial view, because I can't get that to work. It only gives me the hidden field Steven Sanderson talks about, but not the actual textbox. So I tried commenting that part out and just had a textbox. Well, that gets me the textbox, but I can't get to that info in the post method. I use the Consultant object as return parameter, but the Programs property contains no Program. Perhaps this has to do with the fact that I cannot get the BeginCollectionItem helper to work, but in any case I don't understand how to do that, or how to get to the Program supposedly added in the view. With a simple object I would add the new object in the post method by something like _repository.AddToConsultants(consultant), and when I save to EF it gets its id. But how do I do the same thing with the program object and save it to the database via EF?