roryok
roryok

Reputation: 9645

How to do Semi-Required attributes in ASP MVC?

I've got an MVC app which features a DropDownList and TextBox. I'm using MVC validation and I'm happy with it.

At the moment The DropDownList is [Required], but I want to make it so the TextBox can function as an 'other: please specify' style input for the DropDownList.

How do I make it so that the [Required] attribute on the DropDownList is conditional on the TextBox being empty?

This question is similar, but it's over a year old. Anything in the current version of MVC that makes this easy to do?

Upvotes: 3

Views: 928

Answers (2)

Darin Dimitrov
Darin Dimitrov

Reputation: 1039478

It would be pretty easy to write a custom validation attribute:

public class RequiredIfPropertyIsEmptyAttribute : RequiredAttribute
{
    private readonly string _otherProperty;
    public RequiredIfPropertyIsEmptyAttribute(string otherProperty)
    {
        _otherProperty = otherProperty;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var property = validationContext.ObjectType.GetProperty(_otherProperty);
        if (property == null)
        {
            return new ValidationResult(string.Format("Unknown property {0}", _otherProperty));
        }

        var otherPropertyValue = property.GetValue(validationContext.ObjectInstance, null);
        if (otherPropertyValue == null)
        {
            return base.IsValid(value, validationContext);
        }
        return null;
    }
}

then you could have a view model:

public class MyViewModel
{
    public string Foo { get; set; }

    [RequiredIfPropertyIsEmpty("Foo")]
    public string SelectedItemId { get; set; }

    public IEnumerable<SelectListItem> Items {
        get
        {
            return new[] 
            {
                new SelectListItem { Value = "1", Text = "item 1" },
                new SelectListItem { Value = "2", Text = "item 2" },
                new SelectListItem { Value = "3", Text = "item 3" },
            };
        }
    }
}

A controller:

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

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        return View(model);
    }
}

And of course a view:

@model MyViewModel

@using (Html.BeginForm())
{
    <div>
        @Html.LabelFor(x => x.Foo)
        @Html.EditorFor(x => x.Foo)
    </div>
    <div>
        @Html.LabelFor(x => x.SelectedItemId)
        @Html.DropDownListFor(x => x.SelectedItemId, Model.Items, "-- select an item --")
        @Html.ValidationMessageFor(x => x.SelectedItemId)
    </div>

    <input type="submit" value="OK" />
}

or you could do as I do: download and use the FluentValidation.NET library, forget about data annotations and write the following validation logic which seems pretty self-explanatory:

public class MyViewModelValidator: AbstractValidator<MyViewModel> 
{
    public MyViewModelValidator() 
    {
        RuleFor(x => x.SelectedItemId)
            .NotEmpty()
            .When(x => !string.IsNullOrEmpty(x.Foo));
    }
}

Just go ahead and Install-Package FluentValidation.MVC3 and make your life easier.

Upvotes: 8

jrummell
jrummell

Reputation: 43107

You can create a ConditionalAttribute.

ASP.net MVC conditional validation

ASP.NET MVC Conditional validation

Upvotes: 1

Related Questions