Hello out there in internet land, I have an interesting conundrum for you:
Is it possible to bind a view for creating an object, if that object contains a list of other objects purely using MVC views/partial views?
Man, that came out all complicated like...let me give you a quick code example of what I mean:
Models:
public class ComplexObject
{
public string title { get; set; }
public List<ContainedObject> contents { get; set; }
}
public class ContainedObject
{
public string name { get; set; }
public string data { get; set; }
}
Nice and simple right? Okay, so a strongly typed view for creating one of these is really simple for the "title" property:
something like:
@Html.TextBoxFor(x => x.title)
but I can't figure out a good way to bind a list of "ContainedObjects" using MVC. The closest that I got was to create a strongly-typed IEnumerable partial view with the "List" scaffold template and include that on the page.
Without adding styling etc, the default look of that partial view is:
@model IEnumerable<MVCComplexObjects.Models.ContainedObject>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table>
<tr>
<th>
@Html.DisplayNameFor(model => model.name)
</th>
<th>
@Html.DisplayNameFor(model => model.data)
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
@Html.DisplayFor(modelItem => item.name)
</td>
<td>
@Html.DisplayFor(modelItem => item.data)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
</table>
But frankly, I can't figure out how to include that as bound to the creation of a new ComplexObject. In other words, I can show a list of already existing ContainedObjects by binding as so: @Html.Partial("PartialCreate", Model.contents)
But what I really want I guess, is something like:
@Html.PartialFor("PartialCreate", x => x.contents)
I should note that I didn't have too much trouble coding around this with Javascript (I'll include the code below) but I'd really like to know if there's a way to do this purely with MVC. I'm a recent convert from WebForms (where I'd pretty much just replaced all of my postbacks with AJAX calls anyway) and this sort of thing comes up a lot in projects that I work on.
Anyway, here's how I currently do it:
Html -
Name: <input type="text" id="enterName" />
Data: <input type="text" id="enterData" />
<a id="addItem">Add Item</a>
<ul id="addedItems">
</ul>
<a id="saveAll">Save Complex Object</a>
Javascript -
<script>
var contents = [];
$(document).ready(function () {
$('#addItem').click(function () {
var newItem = { name: $('#enterName').val(), data: $('#enterData').val() };
contents.push(newItem);
$('#addedItems').html('');
for (var i = 0; i < contents.length; i++) {
$('#addedItems').append(
"<li>" + contents[i].name + ", " + contents[i].data + "</li>"
);
}
});
$('#saveAll').click(function () {
var toPost = { title: "someTitle", contents: contents };
$.ajax({
url: '/Home/SaveNew',
type: 'POST',
data: JSON.stringify(toPost),
dataType: 'json',
contentType: 'application/json; charset=utf-8',
success: function (data, textStatus, jqXHR) {
alert("win");
},
error: function (objAJAXRequest, strError) {
alert("fail");
}
});
});
});
</script>
And that's not a terrible solution or anything, I just don't want to have to implement Javascript calls everytime I want to save a new object, but use standard Razr code everywhere else. I'd like to be reasonably consistent across the board.
Has anyone else run into this issue and found a solution?