Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC2 Client-Side Validation for injected Ajax content

I am making an Ajax call and adding content to a form inside a MVC2 app. I need to update the Client Validation Metadata with the validation for my new content.

 <script type="text/javascript"> 
//<![CDATA[
if (!window.mvcClientValidationMetadata) { window.mvcClientValidationMetadata = []; }
window.mvcClientValidationMetadata.push({"Fields":[{"
...
</script>

Is there a way to generate this metadata for a partial view ?

Thanks in advance.

like image 640
Radu Negrila Avatar asked May 18 '10 13:05

Radu Negrila


3 Answers

I was banging my head against a wall for a few days on this too and was going to go down the route of removing the form tag, but have just got it working in a slightly less hacky way if you are still interested. My scenario was similar in that I have a form with a collection of elements to validate initially, but users can dynamically add new rows via ajax.

I'll break it down so hopefully it'll be easier to see what is going on. Looking at the MVC source code, the form and validation works roughly as so:

Html.BeginForm() outputs the opening form tag then creates and returns a new instance of MvcForm, which doesn't outwardly do much except make the scope of the form easier to manage for you. It does however create a new FormContext and stores this within ViewContext.FormContext. It is this FormContext that tracks the client validation.

The last thing Html.BeginForm() does is set the FormId property of the new FormContext, using the id of the form tag. This is required so the client script can match up forms and validation rules.

Html.EndForm() disposes the MvcForm. This Dispose method outputs the form closing tag and then calls ViewContext.OutputClientValidation() which is resposible for outputting the javascript. Lastly it removes the current FormContext and sets it back to the parent FormContext or null if there isn't one.

So to not output the form tag we somehow need to take some of the FormContext management out of the MvcForm constructor/destructor.

So within my Partial View I did the following:

At the top I check if the ViewContext.FormContext has a value. If so we we are in the initial load so no need to mess around. If not, it is an ajax call, so I enable client validation, create a new MvcForm directly (not with BeginForm) - this causes a FormContext to be created - and set the FormContext.FormId to the same as my parent page

At the end of the view, I check if I have a form instance and if so, call ViewContext.OutputClientValidation() and reset the ViewContext.FormContext to null. I do not Dispose() the MvcForm as this would output the closing tag and MvcForm does not contain disposable objects.

The skeleton of the view looks as so:

<%
MvcForm dummyForm = null;
if (this.ViewContext.FormContext == null)
{
    Html.EnableClientValidation();
    dummyForm = new MvcForm(this.ViewContext);
    this.ViewContext.FormContext.FormId = "mainform";
}
%>

// standard partial view markup goes here

<%
if (dummyForm != null)
{
    this.ViewContext.OutputClientValidation();
    this.ViewContext.FormContext = null;
}
%>

You could quite easily wrap this up into an extension method

Phil

like image 113
Phil Avatar answered Nov 15 '22 04:11

Phil


Finally got it to work.

The answer is simple: don't waist time with MicrosoftMvcValidation.js. It is generated with Script# which makes it difficult to extend.

Switch to xVal and jQuery Validation. It doesn't need a form to generate the client validation metadata. Also in order to load validation for a AJAX request all you have to do is to call the following after you have the new Html:

lForm.find("#placeholder").empty();                     
lForm.valid();
lForm.find("#placeholder").html(responseHtml);   

That does it. First you remove the old content. Than re-run validation to get rid of potentially obsolete validation errors. Than add the new content. Works like a cham.

Also jQuery Validation makes it really easy to enable or disable validation for a certain field (conditional validation).

like image 31
Radu Negrila Avatar answered Nov 15 '22 05:11

Radu Negrila


I have the same problem and resolve using the Future files, and in MicrosoftMvcJQueryValidation.js I change the and of file, this:

$(document).ready(function () {
    var allFormOptions = window.mvcClientValidationMetadata;
    if (allFormOptions) {
        while (allFormOptions.length > 0) {
            var thisFormOptions = allFormOptions.pop();
            __MVC_EnableClientValidation(thisFormOptions);
        }
    }
});

for:

function chargeValidation() {
    var allFormOptions = window.mvcClientValidationMetadata;
    if (allFormOptions) {
        while (allFormOptions.length > 0) {
            var thisFormOptions = allFormOptions.pop();
            __MVC_EnableClientValidation(thisFormOptions);
        }
    }
}

and in content after close form using I call the 'chargeValidation()', this resolve for me the problem I have using $.get(action) containing a form validation.

I hope to help you!

like image 42
ggrocco Avatar answered Nov 15 '22 04:11

ggrocco