Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
424 views
in Technique[技术] by (71.8m points)

asp.net mvc - MVC Custom Validation for List on Client Side

I'm trying to write a custom validator that works on the client side that validates that all checkboxes have been ticked.

Here's the declaration on the model:

[DeclarationsAccepted(ErrorMessage = "You must tick all declarations")]        
    public IList<DeclarationQuestion> DeclarationQuestions { get; set; }

And here's the attribute:

public class DeclarationsAccepted : ValidationAttribute, IClientValidatable
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {

        var questions = value as IList<DeclarationQuestion>;

        if (questions != null && questions.All(c => c.Answer))
        {
            return ValidationResult.Success;
        }
        return new ValidationResult("You must accepted all declarations to continue");
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var modelClientValidationRule = new ModelClientValidationRule
        {
            ValidationType = "declarationsaccepted",
            ErrorMessage = FormatErrorMessage(metadata.DisplayName)
        };            
        yield return modelClientValidationRule;
    }
}

So far so good, works server side.

For the client I'm wiring this up as follows:

jQuery.validator.addMethod('declarationsaccepted', function (value, element, params) {

        //Implement logic here to check all boxes are ticked
        console.log(value);

        return false;
    }, '');


    jQuery.validator.unobtrusive.adapters.add('declarationsaccepted', {}, function (options) {
        options.rules['declarationsaccepted'] = true;
        options.messages['declarationsaccepted'] = options.message;
    });

I'm displaying the checkboxes like this:

@{ var questionIndex = 0; }
        @foreach (var question in Model.DeclarationQuestions)
        {

                @Html.CheckBoxFor(model => Model.DeclarationQuestions[questionIndex].Answer, new { id = "DeclarationQuestions" + questionIndex})

            questionIndex++;
        }

And then displaying the validation message using this:

@Html.ValidationMessageFor(c => c.DeclarationQuestions)

When I submit the form the message is displayed but only after a post back to the server. Is there any way to get this to work on the client side?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The reason you will not get client side validation is because the html helpers generate data-val-* attributes for controls associated with properties. jquery.validate.unobtrusive reads those attributes when the form is parsed and using rules, displays an error message in the appropriate element generated by ValidationMessageFor() associated with that control (it does this by matching up the id attributes of the elements - the error message is generated in a span with <span for="TheIdOfTheAssociatedControl" ...>).

You don't (and cant) generate a control for property DeclarationQuestions (only for properties of each item in DeclarationQuestions so there is nothing that can be matched up.

You could handle this by including your own error message placeholder and intercepting the .submit event

html (add css to style #conditions-error as display:none;)

<span id="delarations-error" class="field-validation-error">
  <span>You must accept all declarations to continue.</span>
</span>

Script

var declarationsError = $('#delarations-error');
$('form').submit(function() {
  var isValid = $('.yourCheckBoxClass').not(':checked') == 0;
  if(!isValid) {
    declarationsError.show(); // display error message
    return false; // prevent submit
  }
});

$('.yourCheckBoxClass').change(function() {
  if($(this).is(':checked')) {
    declarationsError.hide(); // hide error message
  }
});

Side note: You loop for generating the checkboxes should be

for (int i = 0; i < Model.DeclarationQuestions.Count; i++)
{
  @Html.CheckBoxFor(m => m.DeclarationQuestions[i].Answer, new { id = "DeclarationQuestions" + i})
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...