The issue you're encountering with not retaining entries in the collection when adding new entries via PartialView in an MVC application often stems from the way the model state is managed during the AJAX requests. When you update the view with a PartialView, the model state is not preserved between requests, causing the entries to be lost.
Here's a more detailed solution to ensure that the entries are retained:
-
Store the Current State in a Hidden Field: Store the current state of the Details
list in a hidden field so it can be included in the model during subsequent requests.
-
Update the JavaScript to Handle the Hidden Field: Modify the JavaScript to read and update this hidden field.
-
Update the Controller to Use the Updated List: Ensure the controller merges the new entries with the existing entries.
Here's how you can implement these changes:
Step 1: Update the View
Add a hidden field to store the current state of the Details
list:
@model Permit.MasterDtlViewModel
<div class="col-md-12">
@using (Html.BeginForm())
{
@Html.HiddenFor(m => m.Details)
<div class="panel-group">
<!-- Master Info Section -->
<div class="panel panel-success">
<div class="panel-heading">
<div class="panel-title">Master</div>
</div>
<div class="panel-body">
<div class="form-group row">
@Html.LabelFor(m => m.Master.id, "Customer Id", new { @class = "control-label col-md-4" })
<div class="col-md-4">
@Html.TextBoxFor(m => m.Master.id, null, new { @class = "form-control" })
</div>
</div>
<div class="form-group row">
@Html.LabelFor(m => m.Master.name, "Customer Name", new { @class = "control-label col-md-4" })
<div class="col-md-4">
@Html.TextBoxFor(m => m.Master.name, null, new { @class = "form-control" })
</div>
</div>
</div>
</div>
<!-- Detail Info Section -->
<div class="panel panel-success">
<div class="panel-heading">
<div class="panel-title">Detail Info</div>
</div>
<div class="panel-body">
<div class="form-group row">
@Html.Label("DataName", "Data Name", new { @class = "control-label col-md-4" })
<div class="col-md-4">
@Html.TextBox("DataName", null, new { @class = "form-control" })
</div>
</div>
<div class="form-group row">
@Html.Label("DataValue", "Data Value", new { @class = "control-label col-md-4" })
<div class="col-md-4">
@Html.TextBox("DataValue", null, new { @class = "form-control" })
</div>
</div>
<div class="col-md-4 col-md-offset-4">
<input type="button" id="AddButton" value="Add" class="btn btn-info" />
</div>
</div>
</div>
</div>
<!-- Table to display details -->
<div class="panel-group">
<div class="panel panel-success">
<div class="panel-heading">
<div class="panel-title">Added Details</div>
</div>
<div id="dtlTable">
@Html.Partial("_tableDetailView", Model)
</div>
</div>
</div>
<!-- Submit button -->
<div class="col-md-4 col-md-offset-4">
<input type="submit" value="Save" class="btn btn-success" />
</div>
}
</div>
@section scripts {
<script>
$("#AddButton").click(function () {
var mainModel = @Html.Raw(Json.Encode(Model));
var dataName = $("#DataName").val();
var dataValue = $("#DataValue").val();
var newEntry = {
id: 0,
data_name: dataName,
data_val: dataValue
};
// Append new entry to hidden field data
var currentDetails = $("#Details").val();
var detailsArray = currentDetails ? JSON.parse(currentDetails) : [];
detailsArray.push(newEntry);
$("#Details").val(JSON.stringify(detailsArray));
$.ajax({
type: "POST",
url: '@Url.Action("AddNewEntry", "YourControllerName")',
contentType: "application/json",
data: JSON.stringify({ model: mainModel, newEntry: newEntry }),
success: function (result, status, xhr) {
$("#dtlTable").html(result).show();
$("#DataName").val("");
$("#DataValue").val("");
},
error: function (xhr, status, error) {
// Handle error
}
});
});
</script>
}
Step 2: Update the Controller
In the AddNewEntry
action, merge the new entry with the existing entries from the hidden field:
// POST
public ActionResult AddNewEntry(MasterDtlViewModel model, DetailInfo newEntry)
{
if (model.Details == null)
{
model.Details = new List<DetailInfo>();
}
model.Details.Add(newEntry);
return PartialView("_tableDetailView", model);
}
Step 3: Ensure Partial View is Correct
Make sure the partial view correctly displays the details:
@model Permit.MasterDtlViewModel
<div class="panel-body">
<table class="table table-bordered table-hover table-striped table-responsive">
<thead>
<tr>
<td>Idx</td>
<td>Data Name</td>
<td>Value</td>
</tr>
</thead>
<tbody>
@if (Model.Details != null)
{
for (int i = 0; i < Model.Details.Count; i++)
{
<tr>
<td>@Html.HiddenFor(m => m.Details[i].id) @Model.Details[i].id</td>
<td>@Html.HiddenFor(m => m.Details[i].data_name) @Model.Details[i].data_name</td>
<td>@Html.HiddenFor(m => m.Details[i].data_val) @Model.Details[i].data_val</td>
</tr>
}
}
</tbody>
</table>
</div>
Explanation
- Hidden Field for Details: This field ensures that the current state of the details list is persisted across requests.
- JavaScript Handling: The
AddButton
click event handler reads the current state from the hidden field, appends the new entry, and updates the hidden field before making the AJAX request.
- Controller Update: The controller merges the new entry with the existing details and returns the updated partial view.
This approach ensures that each new entry is added to the collection, and the updated list is displayed correctly in the view.