我有一个视图Contact
,可以加载n
个Caller
个部分视图,m
个Child
个部分视图和一个{{} 1}}部分视图在文档准备好后通过Ajax加载。
我也可以添加和删除CallNote
和Callers
,因此这些数字不是静态的。
Children
,删除了一些内容:
Contact.cshtml
我的JS脚本片段@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")
}
:
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
,因此失去了所有的变化。
我应该/我可以做些什么来处理这种情况?
答案 0 :(得分:0)
使用deloopkat's comment,我能够将其工作(大部分时间)
我更改了我的Contact
页面以使用Ajax.BeginForm()
,并在我要用部分视图结果替换的部分添加了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>
}
我创建了一个单独的部分视图_PartialCallDetail
,它可以在现场呈现每个Caller
,Child
和CallNote
的PartailView,而不是通过Ajax调用函数$(document).ready()
...
@* 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.
然后我将提交功能更改为:
[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内容,因此用户必须筛选视图以查看错误。但我觉得这是朝着正确方向迈出的一步