Search code examples
asp.net-mvc-2client-side-validation

Dynamic controls with mvc client validation


I have an MVC 2 app and I am using client side validation. The form has a portion of it where the fields are built dynamically from the database. I want to also allow client side validation for any field that is supposed to be a totalled field (numeric).

So, I took the big blob of validation code and built a matching statement

//<![CDATA[
if (!window.mvcClientValidationMetadata) { window.mvcClientValidationMetadata = []; }
window.mvcClientValidationMetadata.push({ "Fields":
        [{ "FieldName": "<%= id %>", "ReplaceValidationMessageContents": true, "ValidationMessageId": "<%= id %>_validationMessage", "ValidationRules":
            [{ "ErrorMessage": "You must enter an <%= id %>", "ValidationParameters": {}, "ValidationType": "required" },
                { "ErrorMessage": "The <%= id %> must be more than $0.00", "ValidationParameters": { "minimum": 0.01, "maximum": 1.7976931348623157E+308 }, "ValidationType": "range" },
                { "ErrorMessage": "The field <%= id %> must be a number.", "ValidationParameters": {}, "ValidationType": "number" }
        ]}], "FormId": "new-creditcard-form", "ReplaceValidationSummary": false, "ValidationSummaryId": "CreditCardSummary"
});

//]]>

This causes no errors. When the page loads, however, only the validation generated by my data annotations/controls is displayed. What I assume is the error is that my validations are being pushed onto the stack, the server generated validation is the last on the stack, and only one item is being used to validate, the last one on/first one off.

Any ideas how I can get this to work right?

EDIT:

I have discovered that if I call a method called __MVC_EnableClientValidation that resides in MicrosoftMvcJQueryValidation.cs right after building the validation fields, it ignores any other validation definitions. Somehow, I will need to inject my validation into the big validation field definition. so that when __MVC_EnableClientValidation is called, all of them are registered at once.


Solution

  • I figured this out. I needed to use splice instead of push

    <% if (Model.HasCustomValidation) { %>
    //<![CDATA[
    if (!window.mvcClientValidationMetadata) { window.mvcClientValidationMetadata = []; }
    window.mvcClientValidationMetadata.splice(0,0,{ "Fields":
            [{ "FieldName": "<%= id %>", "ReplaceValidationMessageContents": true, "ValidationMessageId": "<%= id %>_validationMessage", "ValidationRules":
                [
                    <% if (Model.EnableTotalledValidation) { %>
                        { "ErrorMessage": "The <%= Model.Column.Name %> in row <%= Model.RowNumber %> cannot be empty.", "ValidationParameters": {}, "ValidationType": "required" },
                        { "ErrorMessage": "The <%= Model.Column.Name %> in row <%= Model.RowNumber %> must be a number.", "ValidationParameters": {}, "ValidationType": "number" }
                    <% } %>
    
                    <% if(Model.EnableTotalledValidation && (Model.EnableRegexValidation || Model.EnableLengthValidation)) { %>
                        ,
                    <% } %>
    
                    <% if(Model.EnableRegexValidation) { %>
                        {"ErrorMessage":"<%: Model.Column.ClientSideRegexErrorMessage %>","ValidationParameters":{"pattern":"<%: Model.Column.ClientSideRegex %>"},"ValidationType":"regularExpression"}
                    <% } %>
                ]
            }], "FormId": "new-creditcard-form", "ReplaceValidationSummary": false, "ValidationSummaryId": "CreditCardSummary"
    });
    //]]>
    
    <% } %>