I would like to add items to a list in my model dynamically with java script. How can I make MVC bind the new item to the model?
My models:
public class Garage
{
public string Name{ get; set; }
public string Location { get; set; }
public IList<Car> Cars{ get; set; }
}
public class Car
{
public string Color{ get; set; }
public string Name { get; set; }
}
My view, which uses a Garage as model:
<% using (Html.BeginForm())
{%>
<div id="cars">
<%
foreach (var item in Model.Cars)
{
Html.RenderPartial("CarView", item);
} %>
</div>
<% } %>
And my CarView which uses a Car as model:
<div class="carRow">
<%-- Color--%>
<%=Html.CustomLabelFor(model => model.Color)%>
<%= Html.TextBox(Model.Color) %>
<%-- Name--%>
<%=Html.CustomLabelFor(model => model.Name)%>
<%= Html.TextBox(Model.Name) %>
</div>
When adding a new Car, I uses a AJAX call, and adds it to the html. The AJAX uses this method in the controller:
public ViewResult NewCar()
{
return View("CarView");
}
My java script ajax call:
$('.addCarButton').click(function () {
$.ajax({
url: "<%= Url.Action("CreateCars") %>",
cache: false,
success: function (html) { $("#cars").append(html); }
});
return false;
});
This renders the html nicely, but it does not add the car to the list of cars.
How can this be done?
You may take a look at the following article
in which Steven Sanderson provides a step by step tutorial on how to implement this.
I realize that this is an old question, but after trying the above suggestion re Steven Sanderson's BeginCollectionItem, and a number of other potential solutions, I did not get very far (new items would not post). BeginCollectionItem seemed like a nice solution in theory, but it would not post new items, and it had unexpected effects on formatting of the list items.
The solution wound up being surprisingly simple, and did not require any external libraries (beyond JQuery). This works for me in ASP.NET MVC5.
path: Views/Shared/EditorTemplate/NuggetSourceDto.cshtml
@model [namespace].NuggetSourceDto
@{
ViewBag.Title = "NuggetSourceDto";
}
<li [email protected]>
@Html.HiddenFor(t => t.Id)
@Html.TextBoxFor(s => s.Url, new { @class = "form-control", autofocus = "autofocus" })
<a role="button" class="glyphicon glyphicon-remove"></a>
</li>
In my view:
@Html.EditorFor(m => m.NuggetSources);
MVC controller get method:
[HttpGet]
public PartialViewResult AddBlankSourcesRow()
{
return PartialView("EditorTemplates/NuggetSourceDto", new NuggetSourceDto());
}
js handler:
$(document).ready(function () {
$('#addSourceBtn').click(function () {
var indexOfNewItem = $('#sourceList li').length;
$.ajax({
url: '/nugget/AddBlankSourcesRow/',
cache: false,
success: function (html) {
var newItem = $(html);
var randId = Math.random() * 10000000;
randId = Math.floor(randId);
newItem.attr('id', 'newSource__' + randId);
newItem.find('input').first().attr({
//name: 'NuggetSources[3].Id'
name: 'NuggetSources[' + indexOfNewItem + '].Id',
id: 'NuggetSources_' + indexOfNewItem + '__Id',
value: randId
});
newItem.find('input[id^=Url]').attr({
name: 'NuggetSources[' + indexOfNewItem + '].Url',
id: 'NuggetSources_' + indexOfNewItem + '__Url'
});
$('#sourceList').append(newItem);
}
});
return false;
});
});
The lynchpin in all of this is to ensure that the newly-inserted element has a name attribute for each property that includes the name of the collection and a valid index:
newItem.find('input').first().attr({
//name: 'NuggetSources[3].Id'
name: 'NuggetSources[' + indexOfNewItem + '].Id'
});
newItem.find('input[id^=Url]').attr({
name: 'NuggetSources[' + indexOfNewItem + '].Url'
});
Without this, the new items are ignored in the MVC controller.
This solution only handles adding new rows. For deletions, because the indexing is important, one solution is to fire a delete request to the server and then reload the list, or just fix the existing indices in js.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With