Как проверить несколько загруженных Ajax частичных представлений? - PullRequest
0 голосов
/ 30 мая 2018

У меня есть представление, Contact, которое загружает n количество Caller частичных представлений, m количество Child частичных представлений и одно CallNote частичное представление - все загружается через Ajax после того, как документготов.

Я также могу добавлять и удалять 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, таким образом теряя все изменения.

Что я должен / могу сделать, чтобы справиться с этим сценарием?

1 Ответ

0 голосов
/ 31 мая 2018

С комментарием deloopkat я смог получить эту работу (по большей части)

Я изменил свою страницу Contact на использование Ajax.BeginForm() и добавил partialCallDetailидентификатор раздела, который я хочу заменить на результат частичного просмотра:

@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 sPartailView на месте, а не вызов функции через 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(...) s

Я думаю, что важно отметить, что это не идеально в текущем состоянии:

  • Теперь у меня есть два вида, Contact и _PartialCallDetail, которые мне нужно обновить, если явнесите изменения в дизайн в будущем.
  • * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 1034.* И пара других специфических для моего кода проблем, но я их опущу.

Но я чувствую себя довольно хорошо, что это шаг в правильном направлении

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...