0

I'm working with .NET Framework / MVC 4 / C#. I have a View that contains a Partial View which I update/refresh depending on user actions which include clicking a SAVE or CANCEL button. An Ajax request calls a Controller method which returns a Partial View with a blank model to refresh the View. THE PROBLEM is that when returning to the Ajax call from the Controller method, the HTML that the Ajax call presents is the OLD HTML from the Partial View that I am trying to replace??? The model returned by the Controller method is definitely blank, but the Ajax request is not getting it for some strange reason.

After the user clicks either button:

  1. A javascript function is triggered.
  2. The Form inside the Partial View is serialized (hidden inputs, text boxes, and dropdowns).
  3. The serialized Form data is passed into an Ajax request which calls a Controller method and passes in the data.
//Submit a New Payment
$('#paymentpartial').on("click", ".savepayment", function () {
    event.preventDefault();
    var $form = $('form');
    if ($form.valid()) {
        var form = $form.serialize();
        //Save
        $.ajax({
            url: '/Payments/SavePayment',
            datatype: "json",
            traditional: true,
            data: form,
            cache: false,
            success: function (html) {
                $("#paymentpartial").html(html);
                oTable.fnDraw();
            },
            //AJAX call failed
            error: function (data, status, errorThrown) { alert(status + ", " + errorThrown); }
        });
    }
    return false;
});
  1. Controller method does stuff and returns a Partial View with a blank model.

    public ActionResult SavePayment(PaymentSummaryVM model)
    {
        try
        {
            //Save Stuff Here
            //Build a brand new model for the Partial View
            PaymentSummaryVM newModel = new PaymentSummaryVM();
            newModel.ParticipantId = model.ParticipantId;
            List<PaymentType> pTypes = db.PaymentTypes.Where(pt => pt.Active == true).OrderBy(pt => pt.ord).ToList();
            newModel.PaymentTypeList = new SelectList(pTypes, "PaymentTypeId", "Name");
            return PartialView("_AddEditPayment", newModel);
        }
        catch (Exception ex)
        {
            TempData["Error"] = "There were errors while saving your changes. " + ex.Message;
            return RedirectToAction("Index", new { id = model.ParticipantId });
        }
        return RedirectToAction("Index", new { id = model.ParticipantId });
    }
    
    1. On success, Ajax returns the HTML of the Partial View and injects it in a DIV using the jQuery .html() function.
        $.ajax({
            url: '/Payments/SavePayment',
            datatype: "json",
            traditional: true,
            data: form,
            cache: false,
            success: function (html) {
                $("#paymentpartial").html(html);
                }
  1. THE PROBLEM is that the HTML returned by the Controller method, as seen in the Ajax call, is the OLD HTML from the previous Partial View that I'm trying to replace. I'm so confused. Here's the Partial View HTML:
@using BeyondThemes.BeyondAdmin.Models
@model PaymentSummaryVM
@if (Model.PaymentId == 0)
{
    <div class="widget-header bordered-bottom bordered-blue">
        <span class="widget-caption">New Payment</span>
    </div>
}
else
{
    <div class="widget-header bordered-bottom bordered-blue">
        <span class="widget-caption">Edit Payment</span>
    </div>
}
<div class="widget-body" style="margin-bottom:20px">
    @Html.HiddenFor(m => m.ParticipantId)
    @Html.HiddenFor(m => m.PaymentId)
    <div class="row">
        @Html.Bootstrap().LabelFor(m => m.PaymentDate).LabelText("Date:").HtmlAttributes(new { @class = "col-md-1 control-label" })
        <div class="form-group col-md-3">
            @Html.Bootstrap().TextBoxFor(m => m.PaymentDate).Placeholder("Payment Date").HtmlAttributes(new { @class = "form-control" })
            @Html.ValidationMessageFor(m => m.PaymentDate)
        </div>
        @Html.Bootstrap().LabelFor(m => m.PaymentTypeId).LabelText("Type:").HtmlAttributes(new { @class = "col-md-1 control-label" })
        <div class="form-group col-md-3">
            @Html.Bootstrap().DropDownListFor(m => m.PaymentTypeId, Model.PaymentTypeList).OptionLabel("Select a Payment Type").HtmlAttributes(new { @class = "form-control", @id = "creditcard" })
            @Html.ValidationMessageFor(m => m.PaymentTypeId)
        </div>
        @Html.Bootstrap().LabelFor(m => m.Notes).LabelText("Notes:").HtmlAttributes(new { @class = "col-md-1 control-label", @maxlength = "250" })
        <div class="form-group col-md-3">
            @Html.Bootstrap().TextAreaFor(m => m.Notes).HtmlAttributes(new { @class = "form-control", @maxlength = "250" })
            @Html.ValidationMessageFor(m => m.Notes)
        </div>
    </div>
    <div class="form-group col-md-offset-1">
        <div class="row">
            <div class="col-md-1">
            </div>
            <div class="col-md-1">
                <button type="button" class="btn btn-success savepayment" style="width:100%">Save</button>
            </div>
            <div class="col-md-1">
                <button type="button" class="btn btn-default cancelpayment" style="width:100%">Cancel</button>
            </div>
            <div class="col-md-9">
            </div>
        </div>
    </div>
</div>

And it's being injected from the main View like this:

                @using (var form = Html.Bootstrap().Begin(new Form().Type(FormType.Horizontal).HtmlAttributes(new { @id = "paymentpartial" })))
                {
                    Html.RenderPartial("_AddEditPayment", Model);
                }

UPDATE: I just got it to do what I wanted. I had to make the following change, that is, NOT SERIALIZING the form. Just passed in the specific value..Really no clue why this worked but hey..

var pid = $("#ParticipantId").val();
    $.ajax({
        url: '/Payments/GetAddPaymentPartial',
        datatype: "json",
        //traditional: true,
        data: { participantid: pid },
Sam
  • 11
  • 1
  • 5
  • When you say old HTML, do you mean your form still holds values from the original submission? – Mark Sep 15 '15 at 16:59
  • Yes, exactly. It contains all the old model info, so the hidden inputs and text box values are all related to the form that was saved. – Sam Sep 15 '15 at 17:03
  • GET requests can be cached by the browser. Make this a POST request or use various cache-busting techinques. – Jasen Sep 15 '15 at 20:51
  • Tried that but unfortunately it made no difference. Let me point out again that this issue only occurs when I pass data (via Ajax) this way`data: $('form').serialize()`. When I "manually" serialize the data, everything is ok `data: { participantid: pid }`. But of course this makes no sense why this should behave this way! – Sam Sep 17 '15 at 14:01

1 Answers1

0

Try triggering a reset/clear on your success.

 $.ajax({
            url: '/Payments/SavePayment',
            datatype: "json",
            traditional: true,
            data: form,
            cache: false,
            success: function (html) {
                $("#paymentpartial").html(html);
                $("#paymentpartial").find('form')[0].reset();
             }
Mark
  • 4,773
  • 8
  • 53
  • 91
  • That throws an error. But more importantly, it doesn't address the problem that the HTML being returned to the Ajax call is not the same HTML that is being returned by the Controller method. Anyways, I don't want all the inputs in the form to be "reset". I have a hidden input that needs to retain a particular value. – Sam Sep 15 '15 at 17:17
  • Why do you need to pass a partial back anyways? Wouldnt an ajax submit suffice? – Mark Sep 15 '15 at 17:21
  • It sounds like it is coming back correctly, but the values are stored and are being replaced. Can you log the html to console, and verify that these are coming back populated? – Mark Sep 15 '15 at 17:22
  • I'm wondering if the return type of the Controller method makes a difference? ActionResult versus PartialViewResult? – Sam Sep 15 '15 at 17:22
  • I just want the partial to refresh to a blank model so a new payment can be saved quickly. When I hover over the HTML argument returned I can see all the old values are there.. => success: function (html) – Sam Sep 15 '15 at 17:24
  • No need to pass back a partial. Just post to your controller, on success, clear your form. You can set a new model in the controller without passing views around. – Mark Sep 15 '15 at 17:25
  • Will definitely take that into account! Also, see above my post update - got it working by not serializing the form. Weird. – Sam Sep 15 '15 at 17:48
  • http://stackoverflow.com/questions/10011780/prevent-caching-in-asp-net-mvc-for-specific-actions-using-an-attribute – Donnelle Sep 16 '15 at 00:47