簡體   English   中英

如何驗證多個Ajax加載的局部視圖?

[英]How to validate multiple Ajax loaded Partial Views?

我有一個View, Contact ,一旦文檔准備好,它會通過Ajax加載nCaller局部視圖, mChild局部視圖和一個CallNote局部視圖。

我也可以添加和刪除CallersChildren ,因此這些數字不是靜態的。

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");
}

要點是,我有一個加載欄作為每個CallerChildCall Note的占位符,然后在文檔加載時我將它們放在$(document).ready()

我的問題是,當我提交Contact.cshtml並遇到模型驗證錯誤時,我被發送回我的“ Contact頁面,該頁面將重新加載所有CallersChildrenCall 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渲染每個CallerChildCallNote的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 ,如果將來進行設計更改,則需要更新這些視圖。
  • 我在View中擁有的@Html.ValidationSummary()僅適用於非Ajax內容,因此用戶必須在View中進行篩選以查看問題所在。
  • 還有一些其他特定於我的代碼的問題,但我將不贅述。

但是我感到非常高興,這是朝正確方向邁出的一步

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM