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.