Question

My problem is somewhat similar to this problem Custom Validation on group of checkboxes

I have a group of check boxes in the view (New.cshtml) which are rendered using 'ParentObject' as a view model

ParentObject.cs :-

public class ParentObject
{

  [Required]
  public IEnumerable<RegionObject> Regions { get; set; }

}

New.cshtml :-

@model ParentObject

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@using (Html.BeginForm()){   
@Html.LabelFor(model => model.Regions)
@Html.EditorFor(model => model.Regions)
@Html.ValidationMessageFor(model => model.Regions)
<input type="submit" title="Create new parent object" class="button btn67" value="Create" />
}

The editor template for regions is in \Views\Shared\EditorTemplates\RegionObject.cshtml which is like this

@model RegionObject
<p>
@Html.CheckBoxFor(m => m.IsChecked)
@Html.HiddenFor(m => m.Code)
@Html.DisplayFor(m => m.Name)
</p>

The RegionObject view model is :

public class RegionObject
{
   public Guid Code { get; set; }
   public string Name  { get; set; }
   public bool IsChecked { get; set; }
}

Why is the 'Required' data annotation on 'Regions' not working? I want to make sure at least 1 check box is selected against Regions. I would have thought 'Required' would do the job but apparently not. Do I need to write a custom validator to make this work?

Thanks.

Was it helpful?

Solution

The Required attribute cannot operate on collections as you might wish. Also how do you expect it to know that at least one checkbox need to be selected from this RegionObject custom class? How do you expect it to relate the IsChecked property in this collection?

Do I need to write a custom validator to make this work?

Yes, you need a custom validation attribute to achieve that. For example:

public class AtLeastOneRegionMustBeCheckedAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        var instance = value as IEnumerable<RegionObject>;
        if (instance != null)
        {
            return instance.Where(x => x.IsChecked).Count() > 0;
        }
        return base.IsValid(value);
    }    
}

and then:

public class ParentObject
{
    [AtLeastOneRegionMustBeChecked(ErrorMessage = "Please select at least one region")]
    public IEnumerable<RegionObject> Regions { get; set; }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top