0

I have a main view, and this main view has a div tag that will contain a partial view after a Ajax call to the controller.

Here is the partial view responsible for initiating the ajax call:

@model EDR.Presentation.WebMain.ViewModels.MvcPatientDetailsHIVViewModel

<div class="form-group-sm">
    @Html.LabelFor(m => m.HIVTestTestDate, new { @class = "control-label" })
    @Html.EditorFor(m => m.HIVTestTestDate, new { htmlAttributes = new { @class = "form-control form-control-custom-50" } })
</div>

<div class="form-group-sm">
    @Html.LabelFor(m => m.HIVTestTestResult, new { @class = "control-label" })
    @Html.DropDownListFor(m => m.HIVTestTestResult, Model.SelectList_HIVTestedResult, new { @class = "form-control form-control-custom-50" })
</div>

<div class="form-group-sm">
    @Html.LabelFor(m => m.HIVTestCD4Count, new { @class = "control-label" })
    @Html.EditorFor(m => m.HIVTestCD4Count, new { htmlAttributes = new { @class = "form-control form-control-custom-50" } })
</div>

<input type="button" value="Add" id="btnAddNewTest" class="btn btn-info" />
<input type="button" value="Cancel" id="btnCancelAdd" class="btn btn-danger" />

Here is my ajax call:

$('#btnAddNewTest').on("click", function () {
        var date = $('#HIVTestTestDate').val();
        var result = $('#HIVTestTestResult').val();
        var cd4 = $('#HIVTestCD4Count').val();
        var pID = $('#PatientID').val();

        var dataToSend = { patientID: pID, testDate: date, resultID: result, cd4Count: cd4 };

        $.ajax({
            url: '/HIVInformation/AddHIVTest/',
            type: 'post',
            data: dataToSend,
            success: function (partialViewReceived) {
                $('#HIVTestCollection').html(partialViewReceived);
            }
        });
    });

Here is the action in the controller being called by the ajax call:

public PartialViewResult AddHIVTest(Guid patientID, DateTime testDate, Guid resultID, int cd4Count)
        {
            MvcPatientDetailsHIVViewModel model = new MvcPatientDetailsHIVViewModel(patientID);
            model.LoadAllData();

            try
            {
                //add the HIV Test
                model.HIVTestResult = new Common.Models.PatientHIVTestModel()
                {
                    ID = Guid.NewGuid(),
                    PatientID = patientID,
                    TestDate = testDate,
                    HIVTestResultID = resultID,
                    CD4Count = cd4Count
                };

                //call the add method
                model.AddHIVTestResults();
            }
            catch (Exception ex)
            {
                ModelState.AddModelError("", ex);
            }

            return PartialView("_HIVTestCollection", model);
        }

Here is the Partial View loaded after successfully/unsuccessfully attempting to add a new HIV Test.

@model EDR.Presentation.WebMain.ViewModels.MvcPatientDetailsHIVViewModel
@using EDR.Presentation.WebMain.Helpers

@if (Model.PatientHIVTestCollection != null && Model.PatientHIVTestCollection.Count > 0)
{
    <div class="table-responsive">
        <table class="table table-hover">
            <thead>
                <tr>
                    <th>Date</th>
                    <th>Test Result</th>
                    <th>CD4 Count</th>
                    <th>Actions</th>
                </tr>
            </thead>
            <tbody>
                @foreach (var hivTest in Model.PatientHIVTestCollection.OrderByDescending((x) => x.TestDate))
                {
                    <tr>
                        <td>@RazorHelper.ToDateString(() => hivTest.TestDate)</td>
                        <td>@RazorHelper.ToString(() => hivTest.HIVTestResult.DisplayName)</td>
                        <td>@RazorHelper.ToString(() => hivTest.CD4Count)</td>
                        <td>
                            @Ajax.ActionLink("Edit", "EditHIVTest", new { patientID = Model.PatientID, testID = hivTest.ID }, new AjaxOptions() { HttpMethod = "get", InsertionMode = InsertionMode.Replace, UpdateTargetId = "testEdit" }, new { @class = "btn btn-info" })
                            @Ajax.ActionLink("Delete", "DeleteHIVTest", new { patientID = Model.PatientID, testID = hivTest.ID }, new AjaxOptions() { HttpMethod = "get", InsertionMode = InsertionMode.Replace, UpdateTargetId = "HIVTestCollection" }, new { @class = "btn btn-danger" })
                        </td>
                    </tr>
                }
            </tbody>
        </table>
    </div>
}
else
{
    <text>No Data to display</text>
}

I have verified after catching the exception, that the validation message is added to ModelState.

I understand that this Partial View is added dynamically to the Main view, but how can I reset the main view to display the validation message added to ModelState. I do not want to show the validation message in the partial view.

Here is a Partial View also present on the main view for displaying the validation messages.

@model ModelStateDictionary

@if (!Model.IsValid)
{
    <div class="panel panel-danger">
        <div class="panel-heading">Validation Errors</div>
        <div class="panel-body">
            <ul>
                @foreach (var modelError in
                             Model.SelectMany(keyValuePair => keyValuePair.Value.Errors))
                {
                    <li>@modelError.ErrorMessage</li>
                }
            </ul>
        </div>
    </div>
}

Any help would be greatly appreciated.

  • You cant (unless you return the main view). But one option would be to return a collection of the errors as JSON and update and some element(s) in the main view to display them. –  Jan 14 '16 at 08:15
  • @StephenMuecke Do you perhaps have a working sample I can see? Or do you mean that whatever I return, should be displayed where the original Partial View should have been rendered if there was no errors? –  Jan 14 '16 at 08:22
  • I'm curious now what your partial is actually doing. Is that all it contains, or do you have other html? –  Jan 14 '16 at 08:24
  • @StephenMuecke the partial has two "TextBoxes" and a dropdown. When the dropdown selection does not match the overall description of the outcome, the test cannot be added. This is the validation message that I would like to display on the main view –  Jan 14 '16 at 08:26
  • When you return the partial, do the values of the options in the dropdown change from the original? –  Jan 14 '16 at 08:29
  • Not quite sure I know what you mean. After I selected the desired option in the dropdown, click the submit button (ajax call happens here) and there is a error, the selected option is still selected in the dropdown, does not reset to default no. –  Jan 14 '16 at 08:33
  • You stated previously that the partial contains _two "TextBoxes" and a dropdown_ (it was that dropdown was referring to) –  Jan 14 '16 at 08:36
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/100646/discussion-between-akemp-and-stephen-muecke). –  Jan 14 '16 at 08:37

1 Answers1

0

In your AddHIVTest() controller method, there is little point adding a ModelState error. These a designed for use in the ValidationSummary() and ValidationMessageFor() helpers associated with a form, but the associated partial does not have a form. Instead you could just add the error message to a view model or ViewBag property, for example

catch (Exception ex)
{
  ViewBag.ErrorMessage = ex.ToString();
}

which you can then render in that _HIVTestCollection partial as (say)

<div id="errormessage">@ViewBag.ErrorMessage</div>

Then, if you want to display that message in a different location in the main view than where you render the partial, modify the ajax function to move the <div> to a new location. Assuming the main view contains an element

<div id="errorcontainer"><div> // placeholder for the error message
.... // other elements
<div id="HIVTestCollection"><div> // placeholder for the partial

Then

$.ajax({
    url: '/HIVInformation/AddHIVTest/',
    type: 'post',
    data: dataToSend,
    success: function (partialViewReceived) {
        $('#HIVTestCollection').html(partialViewReceived);
        $('#errorcontainer').append($('#errormessage')); // move the message from the partial to the placeholder in the main view
    }
});

Another option would be to generate 2 partial views (one with the errors) and return them as strings (in a JsonResult) using the technique described in this answer.

Community
  • 1
  • 1