[英]How to validate multiple Ajax loaded Partial Views?
我有一個View, Contact
,一旦文檔准備好,它會通過Ajax加載n
個Caller
局部視圖, m
個Child
局部視圖和一個CallNote
局部視圖。
我也可以添加和刪除Callers
和Children
,因此這些數字不是靜態的。
Contact.cshtml
,其中刪除了一些內容:
@using Birth_To_Five.ViewModels
@model CallDetailViewModel
<div class="container">
<ul class="nav nav-tabs">
<li class="active"><a href="#tab-1" role="tab" data-toggle="tab">Call Detail</a></li>
@* Other tabs not shown here *@
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="tab-1">
@using (Html.BeginForm("SubmitCallDetailsAsync", "Home", FormMethod.Post))
{
<div class="well">
@Html.AntiForgeryToken()
@Html.HiddenFor(m => m.Id)
@Html.HiddenFor(m => m.CallThreadViewModel.Id)
<span style="color: red">
@Html.ValidationSummary()
</span>
@* Call Details *@
<div class="row">
<fieldset>
<legend>Call Details</legend>
</fieldset>
</div>
<div class="row">
<div class="form-group">
@Html.LabelFor(m => m.EnteredByEmail, new { @class = "control-label" })
@Html.ValidationMessageFor(m => m.EnteredByEmail, "", new { @class = "text-danger" })
@Html.TextBoxFor(m => m.EnteredByEmail, new { @class = "form-control", placeholder = "Who took the call" })
</div>
@* Other stuff *@
</div>
@* Caller Details *@
<div class="row">
<fieldset>
<legend>Callers</legend>
</fieldset>
</div>
@* Render each existing caller. Each caller gets their own well to create a visual separation between them. *@
@foreach (var callerViewModel in Model.CallerViewModels)
{
<div class="progress" id="callerLoadingBar-@callerViewModel.Id" data-callerid="@callerViewModel.Id" data-calldetailid="@Model.Id">
<div class="progress-bar progress-bar-striped active" role="progressbar" style="width: 100%">Loading Caller...</div>
</div>
}
<div id="newCaller"></div>
<div class="row">
@* Button to search for and add a caller *@
</div>
@* Children Details *@
<div class="row">
<fieldset>
<legend>Children</legend>
</fieldset>
</div>
@* Render each existing child. Each child gets their own well to create a visual separation between them. *@
@foreach (var childViewModel in Model.ChildViewModels)
{
<div class="progress" id="childLoadingBar-@childViewModel.Id" data-childid="@childViewModel.Id" data-calldetailid="@Model.Id">
<div class="progress-bar progress-bar-striped active" role="progressbar" style="width: 100%">Loading Child...</div>
</div>
}
<div id="newChild"></div>
<div class="row">
@* Button to search for and add a child *@
</div>
<div class="progress" id="callNoteLoadingBar">
<div class="progress-bar progress-bar-striped active" role="progressbar" style="width: 100%">Loading Call Note...</div>
</div>
</div>
<div class="row">
<div class="form-group">
<button class="btn btn-danger" type="reset">Reset</button>
</div>
<div class="form-group">
<button class="btn btn-primary" type="submit">Submit</button>
</div>
</div>
}
</div>
</div>
</div>
@section scripts
{
@Scripts.Render("~/bundles/jqueryval")
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js"></script>
@Scripts.Render("~/bundles/calldetailscripts")
}
我的JS腳本中的代碼片段callDetailFunctions
:
$(document).ready(function () {
getCallNote('#callNoteLoadingBar', $('#Id').val());
getAllCallers();
getAllChildren();
});
// function getAllWhatever(){ Foreach loading bar, addCaller/Child/CallNotePartialView(..., ..., ..., etc.); }
function addWhateverPartialView(divToReplace, thingIWantId, callDetailId) {
$.ajax({
url: '/Home/GetWhateverPartialViewAsync',
data: {
thingIWantId,
callDetailId
},
type: "GET",
error: function (xmlHttpRequest, textStatus, errorThrown) {
alert("Request: " + xmlHttpRequest.toString() + "\n\nStatus: " + textStatus + "\n\nError: " + errorThrown);
},
success: function (data) {
$(divToReplace).replaceWith(data);
}
});
}
在我的HomeController
我具有SubmitCallDetailsAsync
方法:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> SubmitCallDetailsAsync(CallDetailViewModel callDetailViewModel)
{
using (var unitOfWork = new UnitOfWork(ApplicationDbContext))
{
// Call Details
var callDetailServices = new CallDetailServices();
await callDetailServices.AddOrUpdateCallDetailFromCallDetailViewModelAsync(callDetailViewModel, ModelState, unitOfWork);
// Callers
var callerServices = new CallerServices();
await callerServices.AddOrUpdateCallersFromCallDetailsViewModelAsync(callDetailViewModel, ModelState, unitOfWork);
// Children
var childServices = new ChildServices();
await childServices.AddOrUpdateChildrenFromCallDetailsViewModelAsync(callDetailViewModel, ModelState, unitOfWork);
// Call Note
var callNoteServices = new CallNoteServices();
await callNoteServices.AddOrUpdateCallNoteFromCallDetailsViewModelAsync(callDetailViewModel, ModelState, unitOfWork);
// Check the model state (returns true if it's good, false otherwise.
// Also spits out some debug text for me to tell me what broke the Model)
if (!UtilityServices.CheckModelState(ModelState))
{
callDetailViewModel.DirectionChoices =
await unitOfWork.DirectionChoiceRepo.GetAllAsSelectListItemsAsNoTrackingAsync();
return View("Contact", callDetailViewModel);
}
await unitOfWork.CompleteAsync();
}
return RedirectToAction("Index");
}
要點是,我有一個加載欄作為每個Caller
, Child
和Call Note
的占位符,然后在文檔加載時我將它們放在$(document).ready()
我的問題是,當我提交Contact.cshtml
並遇到模型驗證錯誤時,我被發送回我的“ Contact
頁面,該頁面將重新加載所有Callers
, Children
和Call Note
,從而丟失所有更改。
我應該/可以做些什么來應對這種情況?
使用deloopkat的評論 ,我能夠使它正常工作(大部分時間)
我將“ Contact
頁面更改為使用Ajax.BeginForm()
,並向partialCallDetail
Partial View結果替換的部分添加了partialCallDetail
ID:
@using (Ajax.BeginForm("SubmitCallDetailsAsync", "Home", new AjaxOptions() {HttpMethod = "POST", UpdateTargetId = "partialCallDetail", OnSuccess = "onSuccess"})) @* <----------- Note the UpdateTargetId *@
{
<div class="well">
@Html.AntiForgeryToken()
@Html.HiddenFor(m => m.Id)
@Html.HiddenFor(m => m.CallThreadViewModel.Id)
<span style="color: red">
@Html.ValidationSummary()
</span>
@* Call Details *@
<div id="partialCallDetail"> @* <------------------ This whole div gets replaced by the Submit function when the Model Validation fails *@
@* All of the same stuff as before in my original post *@
</div>
</div>
<div class="row">
<div class="form-group">
<button class="btn btn-danger" type="reset">Reset</button>
</div>
<div class="form-group">
<button class="btn btn-primary" type="submit">Submit</button>
</div>
</div>
}
@section scripts
{
<script>
function onSuccess(data) {
///<summary>
/// When the Ajax form is submitted, this function gets called with the return data.
/// Determine if it contains a redirectUrl and go there if it does
///</summary>
if (data.redirectUrl !== undefined) {
window.location.replace(data.redirectUrl);
}
}
</script>
}
我創建了一個單獨的Partial View _PartialCallDetail
, _PartialCallDetail
渲染每個Caller
, Child
和CallNote
的PartailView,而不是通過$(document).ready()
上的Ajax調用函數。
...
@* Render each existing caller. Each caller gets thier own well to create a visual seperation between them. *@
@foreach (var callerViewModel in Model.CallerViewModels)
{
Html.RenderPartial("_PartialCallerInfo", callerViewModel);
}
...etc.
然后,將我的Submit函數更改為:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> SubmitCallDetailsAsync(CallDetailViewModel callDetailViewModel)
{
using (var unitOfWork = new UnitOfWork(ApplicationDbContext))
{
// Call Details
var callDetailServices = new CallDetailServices();
await callDetailServices.AddOrUpdateCallDetailFromCallDetailViewModelAsync(callDetailViewModel, ModelState, unitOfWork);
// Callers
var callerServices = new CallerServices();
await callerServices.AddOrUpdateCallersFromCallDetailsViewModelAsync(callDetailViewModel, ModelState, unitOfWork);
// Children
var childServices = new ChildServices();
await childServices.AddOrUpdateChildrenFromCallDetailsViewModelAsync(callDetailViewModel, ModelState, unitOfWork);
// Call Note
var callNoteServices = new CallNoteServices();
await callNoteServices.AddOrUpdateCallNoteFromCallDetailsViewModelAsync(callDetailViewModel, ModelState, unitOfWork);
// Check the model state
if (!UtilityServices.CheckModelState(ModelState))
{
// Setup all drop downs
callDetailViewModel.DirectionChoices =
await unitOfWork.DirectionChoiceRepo.GetAllAsSelectListItemsAsNoTrackingAsync();
foreach (var callerViewModel in callDetailViewModel.CallerViewModels)
{
await callerServices.SetupSelectListItemsAsync(callerViewModel, unitOfWork);
}
foreach (var childViewModel in callDetailViewModel.ChildViewModels)
{
childViewModel.SexChoices = await unitOfWork.SexChoiceRepo.GetAllAsSelectListItemsAsNoTrackingAsync();
}
// Return the ViewModel with Validation messages
if (Request.IsAjaxRequest()) return PartialView("_PartialCallDetail", callDetailViewModel);
return View("Contact", callDetailViewModel);
}
await unitOfWork.CompleteAsync();
}
return Json(new { redirectUrl = Url.Action("Index", "Home", null) });
}
現在,當出現模型驗證錯誤時,我將發回_PartialCallDetail
視圖,該視圖將使用現有數據更新“ Contact
頁面並激活@Html.ValidationMessageFor(...)
我認為必須注意,在當前狀態下這並不完美:
Contact
和_PartialCallDetail
,如果將來進行設計更改,則需要更新這些視圖。 @Html.ValidationSummary()
僅適用於非Ajax內容,因此用戶必須在View中進行篩選以查看問題所在。 但是我感到非常高興,這是朝正確方向邁出的一步
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.