1

For a simple validation of multiple required fields i am using a custom validator explained here

I am getting the desired behavior and validation summary message is displayed correctly, but what i am missing now is the lack of validation error css class on invalid input elements, which is added when built-in validators are used.

This is the correct behavior:

<input class="input-validation-error" name="ModelName" ... />

And this is what i get when using mentioned custom validator:

<input name="ModelName" ... />

Please note that i am referring to server side validation.

UPDATE

This is my model:

public class Register
{
        [MultiFieldRequired(new[] { "Name", "UserName" }, ErrorMessage = "Please provide all required information")]
        [Display(Name = "Name")]
        public string Name { get; set; }

        [MultiFieldRequired(new[] { "Name", "UserName" }, ErrorMessage = "Please provide all required information")]
        [Display(Name = "User name")]
        public string UserName { get; set; }
}

And this is the rendered output:

<input class="text-box single-line" data-val="true" data-val-multifield="Please provide all required information" id="Name" name="Name" type="text" value="" />
<input class="text-box single-line" data-val="true" data-val-multifield="Please provide all required information" id="UserName" name="UserName" type="text" value="" />

I am now realizing that the problem i had only occurs when i decorate my entire model class with the MultiFieldRequired attribute:

[MultiFieldRequired(new[] { "Name", "UserName" }, ErrorMessage = "Please provide all required information")]
public class Register
{
...

In this case no invalid field has modified css class, while in the other scenario, when i annotate every field in the model i get the same error message multiplied by the number of invalid fields.

So, to summarize - i want to have one error message regardless of the number of invalid fields and I also want that each invalid field be marked with .input-validation-error class.

Community
  • 1
  • 1
ljubomir
  • 1,495
  • 1
  • 21
  • 40

2 Answers2

2

I have just tested this and it worked ok. Here's what I did:

Controller:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    [HttpPost]
    public ActionResult Index(IndexModel model)
    {
        if (ModelState.IsValid)
        {
            return RedirectToAction("NextAction");
        }
        return View(model);
    }
}

Model:

public class IndexModel
{
    [MultiFieldRequiredAttribute(new string[] { "AreaCode", "PhoneNumber" })]
    public string AreaCode { get; set; }

    [MultiFieldRequiredAttribute(new string[] { "AreaCode", "PhoneNumber" })]
    public string PhoneNumber { get; set; }
}

I used the validation exactly as it was provided in the example:

public class MultiFieldRequiredAttribute : ValidationAttribute, IClientValidatable
{
    private readonly string[] _fields;

    public MultiFieldRequiredAttribute(string[] fields)
    {
        _fields = fields;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        foreach (string field in _fields)
        {
            PropertyInfo property = validationContext.ObjectType.GetProperty(field);
            if (property == null)
                return new ValidationResult(string.Format("Property '{0}' is undefined.", field));

            var fieldValue = property.GetValue(validationContext.ObjectInstance, null);

            if (fieldValue == null || String.IsNullOrEmpty(fieldValue.ToString()))
                return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
        }

        return null;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        yield return new ModelClientValidationRule
        {
            ErrorMessage = this.ErrorMessage,
            ValidationType = "multifield"
        };
    }
}

View:

@model IndexModel

@using (Html.BeginForm())
{
    @Html.EditorFor(m => m.AreaCode)
    @Html.EditorFor(m => m.PhoneNumber)
    <input type="submit" value="submit" />
}

If you then display the view the following is displayed for the area code:

<input class="text-box single-line" data-val="true" data-val-multifield="" id="AreaCode" name="AreaCode" type="text" value="" />

If you then click the submit button you get the following:

<input class="input-validation-error text-box single-line" data-val="true" data-val-multifield="" id="AreaCode" name="AreaCode" type="text" value="" />

Its when you click the submit button that the input-validation-error is added.

Dangerous
  • 4,818
  • 3
  • 33
  • 48
  • Thanks for the answer. From the first look it looks like everything is working ok. But try setting a valid value for AreaCode and leave PhoneNumber empty. You'll get exactly what i am describing above. – ljubomir May 18 '12 at 16:02
  • @ljubomir - When you enter a value in AreaCode but not PhoneNumber it is reported as an error on the AreaCode field? Do you not get this? From what I gather this is correct as you haven't entered both parts of the multipart field so an error should be reported. If you want the error to be reflected in both fields you would have to provide the same data annotation on the other field. I have updated the answer to reflect this. Do you not get these results? – Dangerous May 18 '12 at 16:18
  • Sorry i was away from my machine. Yes i have the valid field marked with error class, but this is exactly what i'm trying to avoid. I want only invalid fields to be marked and only one error message to be displayed. – ljubomir May 18 '12 at 18:42
  • Thanks for your investigation @Dangerous. You made me realized that i have another problem in hand. I added a detailed explanation of my final solution. – ljubomir May 21 '12 at 11:58
1

I was expecting that invalid fields in the view will be marked with .input-validation-error class regardles of the position of the attribute, so i used the custom validator attribute to annotate my model class like this:

[MultiFieldRequired(new[] { "Name", "UserName" }, ErrorMessage = "Please provide all required information")]
public class Register
{
        [Display(Name = "Name")]
        public string Name { get; set; }

        [Display(Name = "User name")]
        public string UserName { get; set; }
}

On the other hand, if i annotate each field:

public class Register
{
        [MultiFieldRequired(new[] { "Name", "UserName" }, ErrorMessage = "Please provide all required information")]
        [Display(Name = "Name")]
        public string Name { get; set; }

        [MultiFieldRequired(new[] { "Name", "UserName" }, ErrorMessage = "Please provide all required information")]
        [Display(Name = "User name")]
        public string UserName { get; set; }
}

my view generates multiple identical messages in the validation summary.

So i ended up having a a custom validation summary error message using ValidationSummary like this:

@Html.ValidationSummary(true, "Please provide all required information")

and my fields are decorated with simple asterisks like this:

public class Register
{
        [Required(ErrorMessage = "*")]
        [Display(Name = "Name")]
        public string Name { get; set; }

        [Required(ErrorMessage = "*")]
        [Display(Name = "User name")]
        public string UserName { get; set; }
}

At the end, my view is rendered like this:

Validation error messages

HTH

ljubomir
  • 1,495
  • 1
  • 21
  • 40
  • i like to know is there any in-built attribute exist in mvc 3 called MultiFieldRequired for validation purpose or do i need to develop it? thanks – Mou Oct 19 '13 at 19:14