Reputation: 2055
Hi I have a form that uses the following viewmodel
public class MainViewModel
{
public int Id { get; set; }
public List<LotViewModel> Lots { get; set; }
[DisplayName("Number of Lots")]
public int NumberOfFields { get; set; }
}
NumberOfFields is used in a for loop to render LotViewModels. The user selects a number from 1 -> 4 from a drop down. There is a JS function that then uses AJAX that calls a Controller method to render a partial view containing the correct number of fields. This JS function is triggered when the drop down changes.
This is the controller method
[HttpPost]
public PartialViewResult AddLotFields(int numberOfFields)
{
var viewModel = new MainViewModel
{
Lots = new List<LotViewModel>(),
NumberOfFields = numberOfFields
};
return PartialView("~/Areas/Admin/Views/MainController/_LotForm.cshtml", viewModel);
}
And this is the Javascript
$(function() {
$("#numberOfLotsDD").change(function(event) {
$.ajax({
url: window.g_baseUrl + "MainController/AddLotFields/",
data: {
numberOfFields: $(this).val()
},
cache: false,
type: "POST",
dataType: "html",
success: function(data, textStatus, XMLHttpRequest) {
$("#LotFields").html(data);
}
});
});
});
This works fine but when you submit the form the viewModel doesn't contain any elements in Lots.
The partial view that renders the input fields is
@model MainViewModel
@for (var i = 0; i < Model.NumberOfFields; i++)
{
Model.Lots.Add(new LotViewModel());
<div class="row">
<div class="col-md-6">
<div class="form-group ">
@Html.LabelFor(model => model.Lots.Last().BatchIdLocation)
@Html.TextBoxFor(model => model.Lots.Last().BatchIdLocation, new { @class = "form-control", @placeholder = "Enter Batch Id tag" })
@Html.ValidationMessageFor(model => model.Lots.Last().BatchIdLocation)
</div>
</div>
<div class="col-md-6">
<div class="form-group ">
@Html.LabelFor(model => Model.Lots.Last().QuantityLocation)
@Html.TextBoxFor(model => Model.Lots.Last().QuantityLocation, new { @class = "form-control", @placeholder = "Enter Quantity tag" })
@Html.ValidationMessageFor(model => Model.Lots.Last().QuantityLocation)
</div>
</div>
</div>
}
I've messed around with a few ways of trying to save this form but none of it has worked.
I know if I'm really stuck I could use JQuery to send the form input values to my controller. But I would like to avoid that if possible and keep the solution confined to c# and razor
Upvotes: 0
Views: 2457
Reputation: 10849
Suggestion - You can create the items in your collection at server side itselft instead of passing a flag to view to generate numbers of items.
[HttpPost]
public PartialViewResult AddLotFields(int numberOfFields)
{
var lots = new List<LotViewModel>();
for (int index = 0; index < numberOfFields; index++)
{
lots.Add(new LotViewModel());
}
return PartialView("~/Areas/Admin/Views/MainController/_LotForm.cshtml", lots);
}
This will also give you ability to initialize the view model properties with external factor dependent values.
So the changes in view would be as follows :
@model List<LotViewModel>
@for (var i = 0; i < Model.Count; i++)
{
<div class="row">
<div class="col-md-6">
<div class="form-group ">
@Html.LabelFor(model => model.Lots[i].BatchIdLocation)
@Html.TextBoxFor(model => model.Lots[i].BatchIdLocation, new { @class = "form-control", @placeholder = "Enter Batch Id tag" })
@Html.ValidationMessageFor(model => model.Lots[i].BatchIdLocation)
</div>
</div>
<div class="col-md-6">
<div class="form-group ">
@Html.LabelFor(model => model.Lots[i].QuantityLocation)
@Html.TextBoxFor(model => model.Lots[i].QuantityLocation, new { @class = "form-control", @placeholder = "Enter Quantity tag" })
@Html.ValidationMessageFor(model => model.Lots[i].QuantityLocation)
</div>
</div>
</div>
}
The above change will also create the appropriate name at html for each field so that at form post, data post appropriately.
Upvotes: 1
Reputation: 239470
Your field names need to be in the form of Lots[N].PropertyName
, but your field names are being generated as just PropertyName
.
Instead of using model.Lots.Last()
, use the actual index, i.e. model.Lots[i]
.
Upvotes: 1