views:

167

answers:

1

I have a modal popup with a form in it. When submitted via ajax (using jQuery) the form is validated and a javascript callback function checks to see if the model was valid. If so, the modal popup is reset and hidden, if not, the html response text is dumped into the modal popup div for the user to see the fault.

I'm doing this in ASP.NET MVC using a jQuery ajaxSubmit and an action that only accepts a POST verb and returns a PartialViewResult. I do this in several places on my site, but am having problems with 2 such workflows off of 1 page. One works, the other doesn't, using identical code.

Here is the problem:

<% using (Html.BeginForm("ApplyPayment", "SomeController", FormMethod.Post, new { @id = "frmApplyPayment" })) { %>
    <%= Html.AntiForgeryToken(SomeSaltString) %>
    <%= Html.Hidden("ModelValid", ViewData.ModelState.IsValid) %>
    ...
<% } %>

During debugging, even though ViewData.ModelState.IsValid is false when I have validation errors, "#ModelValid" gets set to "True"! I have tried many ways of explicitly setting it to false (like ViewData.ModelState.IsValid ? "True" : "False"). It just always comes out as true even though the variable is false and hides the popup. What is going on?

Here is more code for reference:

function SubmitPaymentForm(form) {
    $(form).ajaxSubmit({ target: "#modalApplyPayment", success: CheckPaymentValidity  });
}

function CheckPaymentValidity(responseText) {
    if ($("#ModelValid").val() != "True") {
        ShowModalPopup("#modalApplyPayment");
    }
    else {
        HideModalPopup("#modalApplyPayment");
    }
}

This all totally works for a very similar workflow off of the same base page for emailing functionality (popup that takes address, validates on ajax post, shows popup if validation error exists).

A: 

The root cause of this problem has to do with how the ModelState is used during a postback and re-rendering of a page. My validation system uses this method:

TrasnferValidationMessagesTo(ModelStateDictionary modelState,
                             IList<IValidationResult> results,
                             FormCollection formValues)
{
    // Set the ModelValue in modelState for each key in formValues

    // Add a ModelError for each error in results
}

I believe ASP's engine is designed to utilize the values in the ModelState collection to repopulate a form's values. This will surreptitiously override my explicit setting of the "#ModelState" hidden field (since hidden fields are captured in form post backs).

Surprisingly, I found that if my ModelState retained the value of "True" for "#ModelValid" from the previous post back, and I tried to set it explicitly to "False" using code, it would not work. But if I reversed it, starting with "False" and setting to "True", it worked fine.

My solution was to add a ModelValid property to my view model and to default it to false and set it to true when there are no validation errors and use that to modify "#ModelValid". I did not have this same problem with my other modal popup because, there, I used manual validation and the ModelState was never updated with the form values from the previous post back.

Chris F