3

If two of textboxes fail validation at once then the ValidationSummary displays the same message twice.

Am I doing something wrong? Or is there a setting I can change to hide duplicate messages?

 

I have broken it down to the simplest example:

View:

@model MyModel
@Html.ValidationSummary()
@Html.TextBoxFor(model => model.A)
@Html.TextBoxFor(model => model.B)

Model:

public class MyModel : IValidatableObject
{
    public int A { get; set; }
    public int B { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        //Some logic goes here.        
        yield return new ValidationResult("Validation failed", new[] { "A", "B" });
    }
}

Result:

enter image description here

Buh Buh
  • 7,443
  • 1
  • 34
  • 61

3 Answers3

9

They are not duplicate from the point of view of ValidationSummary - you are assigning model state error to both fields A and B, so there must be 2 errors in validation summary. It doesnt "know" that they are the same.

Easy solutions :

  • assign model only to one of them
  • exclude property-assigned errors from summary - Html.ValidationSummary(true)

A little bit harder solution :

  • make your own ValidationSummary helper, call standard validation summary logic in it, and then filter the result in "select distinct" way (linq is your friend here).

EDIT:

something like this for example :

public static class ValidationExtensions
{
    public static MvcHtmlString FilteredValidationSummary(this HtmlHelper html)
    {
        // do some filtering on html.ViewData.ModelState 
        return System.Web.Mvc.Html.ValidationExtensions.ValidationSummary(html);
    }
}
rouen
  • 5,003
  • 2
  • 25
  • 48
  • Thanks, I have managed to create my custom helper and it is working great for now. The only problem is that most of it hard coded. You mentioned "standard validation summary logic". Did you have anything specific in mind or was it just a general statement? – Buh Buh Oct 14 '11 at 14:27
2

Whack this is your View

<ul class="validation-summary-errors">
    @{
        string errorMessage = "", previousError = "";
        foreach (ModelState modelState in (ViewContext.ViewData.ModelState.Values)){

            foreach (ModelError modelError in modelState.Errors)
            {
                errorMessage = modelError.ErrorMessage;
                if (errorMessage != previousError)
                {
                    <li>@modelError.ErrorMessage</li>
                    previousError = modelError.ErrorMessage;
                }                            
            }    
        }
    }
</ul>

You might be able to improve this as it only works when 2 consecutive errors are the same, if it jumbles the order this might not work, but this will start you off. I suppose you could build an array of error messages and check the error off it each run through, but this solution seems to work most of the time.

Stuart Dobson
  • 3,001
  • 4
  • 35
  • 37
  • 1
    This particular solution works better if you use a List of errors. As you loop through the errors, use list.Contains() to check if you have already processed an error. If you have not, put it in the list and then display it with
  • tags. T
  • – Chris Holmes Jul 10 '14 at 21:51