在MVC中使用AJAX保存动态数据集(Razor动态生成控件场景)
Here's a practical, step-by-step implementation to handle saving your dynamically generated checkboxes (or any dynamic controls) using AJAX in an MVC Razor view:
1. Define a ViewModel for Clean Binding
First, create a viewmodel structure that mirrors the selection state of your document types. This makes server-side model binding seamless:
public class DocumentTypeSelection { public int DocTypeId { get; set; } public bool IsChecked { get; set; } } // Main viewmodel to hold the collection of selections public class DocumentTypesViewModel { public List<DocumentTypeSelection> SelectedTypes { get; set; } = new List<DocumentTypeSelection>(); }
2. Update the Razor View to Bind Controls to the ViewModel
Modify your dynamic control generation to link each checkbox to the viewmodel collection. This ensures DevExpress generates the correct input names for automatic model binding:
@model DocumentTypesViewModel @{ var docTypes = MyProject.GetDocumentTypes(); // Initialize the viewmodel collection if empty (for first load) if (Model.SelectedTypes.Count == 0) { foreach (var docType in docTypes) { Model.SelectedTypes.Add(new DocumentTypeSelection { DocTypeId = docType.Id }); } } } @Html.DevExpress().FormLayout(settings => { settings.Name = "DocumentTypeForm"; settings.Width = Unit.Percentage(100); var groupItem = settings.Items.AddGroupItem(g => { g.Caption = "Document Types"; }); for (int i = 0; i < docTypes.Count; i++) { var docType = docTypes[i]; groupItem.Items.Add(m => m.SelectedTypes[i].IsChecked, item => { item.Name = $"checkDoc{docType.Id}"; item.NestedExtensionType = FormLayoutNestedExtensionItemType.CheckBox; // Set checkbox label to the document type name ((CheckBoxSettings)item.NestedExtensionSettings).Text = docType.Name; // Add hidden field to track the DocTypeId for each selection item.NestedExtensionSettings.PreRender = (s, e) => { Html.DevExpress().HiddenField(hfSettings => { hfSettings.Name = $"SelectedTypes[{i}].DocTypeId"; hfSettings.Value = docType.Id; }).Render(); }; }); } }).GetHtml() <!-- Save button to trigger AJAX --> @Html.DevExpress().Button(settings => { settings.Name = "SaveButton"; settings.Text = "Save Selections"; settings.ClientSideEvents.Click = "onSaveClick"; }).GetHtml()
3. Client-Side AJAX Logic
Write JavaScript to collect form data, serialize it, and send it to the controller. We'll use jQuery's built-in serialization for simplicity:
function onSaveClick(s, e) { // Serialize all form fields into a format the server can parse var formData = $("#DocumentTypeForm").serializeArray(); // Send AJAX request to the controller $.ajax({ url: '@Url.Action("SaveDocumentTypes", "YourController")', type: 'POST', data: formData, success: function(response) { if (response.success) { alert("Selections saved successfully!"); // Optional: Refresh UI or show confirmation message } else { alert("Error saving: " + response.message); } }, error: function(xhr, status, error) { alert("An unexpected error occurred: " + error); } }); }
4. Server-Side Controller Action
Create a controller action to accept the viewmodel, validate it, and persist the data to your database:
public class YourController : Controller { [HttpPost] public JsonResult SaveDocumentTypes(DocumentTypesViewModel model) { try { if (!ModelState.IsValid) { return Json(new { success = false, message = "Invalid input detected." }); } // Save logic: Update your database based on the selection state foreach (var selection in model.SelectedTypes) { // Example: Toggle active status for the document type // YourDbContext.DocumentTypes // .Where(dt => dt.Id == selection.DocTypeId) // .FirstOrDefault() // .IsActive = selection.IsChecked; } // YourDbContext.SaveChanges(); return Json(new { success = true, message = "Saved successfully." }); } catch (Exception ex) { // Log the exception here for debugging return Json(new { success = false, message = ex.Message }); } } }
Key Takeaways
- Model Binding: The
SelectedTypes[{i}].DocTypeIdandSelectedTypes[{i}].IsCheckednaming convention is critical for ASP.NET MVC to correctly map form fields to your viewmodel. - DevExpress Specifics: The
PreRenderevent adds hidden fields to track each document type's ID, ensuring you know which checkbox corresponds to which record. - Validation: Add data annotations to your viewmodel properties (e.g.,
[Required]) and extend the client-side code to validate before sending the request. - Error Handling: The AJAX handlers provide clear feedback to users, while server-side try/catch blocks handle unexpected issues gracefully.
内容的提问来源于stack exchange,提问作者Bcpouli

