Making ASP.NET MVC 2 client side validation work with AJAX loaded forms
Few days ago I wrote a post in this thread on forums.asp.net. In one of the posts vazavi noticed, that client side validation works only until you reload form using AJAX. I decided to take a deeper look at this. After few hours I have found a solution. The solution depends on which client side validation script you are using (the one which works with jQuery or the one which not). First I will go with the one which doesn't use jQuery. To make it work we need to write one function (I have just added it to MicrosoftMvcValidation.js):
Now we can use our new function as OnSuccess handler for Ajax.BeginForm:
Now it should work. Let's do the same for MicrosoftMvcJQueryValidation.js. We will add the following function inside of it:
We can use this function in the same way as previous one:
I can't say that this solution has been tested in every possible scenario, so if you find any problems with it, just let me know.
Sys.Mvc.FormContext.OnSuccessEnableClientValidation = function (ajaxContext) { //Getting the update target container var updateTarget = document.getElementById(ajaxContext.$4.id); //Getting all script elements in it (script elements injected with innerHtml are not executed) var mvcClientValidationMetadataOldScripts = updateTarget.getElementsByTagName('script'); var mvcClientValidationMetadataNewScripts = []; //For every script element while (mvcClientValidationMetadataOldScripts.length > 0) { //Create a new one var mvcClientValidationMetadataNewScript = document.createElement('script'); mvcClientValidationMetadataNewScript.type = 'text/javascript'; mvcClientValidationMetadataNewScript.text = mvcClientValidationMetadataOldScripts[0].text; //Add it to collection mvcClientValidationMetadataNewScripts.push(mvcClientValidationMetadataNewScript); //And remove old one updateTarget.removeChild(mvcClientValidationMetadataOldScripts[0]); } //For every new script element while (mvcClientValidationMetadataNewScripts.length > 0) { //Append it to update target container, this way they will be executed and generate needed metadata updateTarget.appendChild(mvcClientValidationMetadataNewScripts.pop()); } //Calling Microsoft validation initialization for new metadata Sys.Mvc.FormContext._Application_Load(); }
Now we can use our new function as OnSuccess handler for Ajax.BeginForm:
<% Html.EnableClientValidation(); %> <% using (Ajax.BeginForm("...", "...", null, new AjaxOptions() { UpdateTargetId = "...", OnSuccess = "Sys.Mvc.FormContext.OnSuccessEnableClientValidation" }, new { id = "..." })) { %> ... <% } %>
Now it should work. Let's do the same for MicrosoftMvcJQueryValidation.js. We will add the following function inside of it:
function __MVC_OnSuccessEnableClientValidation(ajaxContext) { //Getting the update target container var updateTarget = document.getElementById(ajaxContext.$4.id); //Getting all script elements in it (script elements injected with innerHtml are not executed) var mvcClientValidationMetadataOldScripts = updateTarget.getElementsByTagName('script'); var mvcClientValidationMetadataNewScripts = []; //For every script element while (mvcClientValidationMetadataOldScripts.length > 0) { //Create a new one var mvcClientValidationMetadataNewScript = document.createElement('script'); mvcClientValidationMetadataNewScript.type = 'text/javascript'; mvcClientValidationMetadataNewScript.text = mvcClientValidationMetadataOldScripts[0].text; //Add it to collection mvcClientValidationMetadataNewScripts.push(mvcClientValidationMetadataNewScript); //And remove old one updateTarget.removeChild(mvcClientValidationMetadataOldScripts[0]); } //For every new script element while (mvcClientValidationMetadataNewScripts.length > 0) { //Append it to update target container, this way they will be executed and generate needed metadata updateTarget.appendChild(mvcClientValidationMetadataNewScripts.pop()); } //Getting new metadata var allFormOptions = window.mvcClientValidationMetadata; if (allFormOptions) { //For every form in metadata while (allFormOptions.length > 0) { //Enable validation for form based on metadata var thisFormOptions = allFormOptions.pop(); __MVC_EnableClientValidation(thisFormOptions); } } }
We can use this function in the same way as previous one:
<% Html.EnableClientValidation(); %> <% using (Ajax.BeginForm("...", "...", null, new AjaxOptions() { UpdateTargetId = "...", OnSuccess = "__MVC_OnSuccessEnableClientValidation" }, new { id = "..." })) { %> ... <% } %>
I can't say that this solution has been tested in every possible scenario, so if you find any problems with it, just let me know.