Reputation: 325
Iam trying to validate textbox based on checkbox value. please view my model class and IsValid override method.
public class Product
{
//Below property value(HaveExperiance)
[MustBeProductEntered(HaveExperiance)]
public string ProductName { get; set; }
public bool HaveExperiance { get; set; }
}
public class MustBeTrueAttribute : ValidationAttribute
{
//Here i need the value of HaveExperiance property which
//i passed from [MustBeProductEntered(HaveExperiance)] in product class above.
public override bool IsValid(object value)
{
return value is bool && (bool)value;
}
}
You can see above in ProductName
property in product
class where iam trying to pass the HaveExperiance
class property value, If it checked then user must have to fill the ProductName
textbox.
So my orignal question is that how can i validate the ProductName
textbox based on the HaveExperiance
value, thanks in advance.
EDIT:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data.Entity;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
namespace Mvc.Affiliates.Models
{
public class MyProducts
{
[Key]
[Required(ErrorMessage = "Please insert product id.")]
public string ProductId { get; set; }
[RequiredIf("HaveExperiance")]
public string ProductName { get; set; }
public bool HaveExperiance { get; set; }
public List<MyProducts> prolist { get; set; }
}
public class RequiredIfAttribute : ValidationAttribute
{
private RequiredAttribute _innerAttribute = new RequiredAttribute();
public string Property { get; set; }
public object Value { get; set; }
public RequiredIfAttribute(string typeProperty)
{
Property = typeProperty;
}
public RequiredIfAttribute(string typeProperty, object value)
{
Property = typeProperty;
Value = value;
}
public override bool IsValid(object value)
{
return _innerAttribute.IsValid(value);
}
}
public class RequiredIfValidator : DataAnnotationsModelValidator<RequiredIfAttribute>
{
public RequiredIfValidator(ModelMetadata metadata, ControllerContext context, RequiredIfAttribute attribute) : base(metadata, context, attribute) { }
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
return base.GetClientValidationRules();
}
public override IEnumerable<ModelValidationResult> Validate(object container)
{
PropertyInfo field = Metadata.ContainerType.GetProperty(Attribute.Property);
if (field != null)
{
var value = field.GetValue(container, null);
if ((value != null && Attribute.Value == null) || (value != null && value.Equals(Attribute.Value)))
{
if (!Attribute.IsValid(Metadata.Model))
{
yield return new ModelValidationResult { Message = ErrorMessage };
}
}
}
}
}
Controller
public class HomeController : Controller
{
//
// GET: /Home/
MvcDbContext _db = new MvcDbContext();
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(MyProducts model)
{
string ProductId = model.ProductId;
string ProductName = model.ProductName;
//bool remember = model.HaveExperiance;
return View();
}
}
View
@model Mvc.Affiliates.Models.MyProducts
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Details</h2>
<br />
<div style="height:200px; width:100%">
@using (Html.BeginForm("Index","Home", FormMethod.Post))
{
<h2>Details</h2>
@Html.LabelFor(model => model.ProductId)
@Html.TextBoxFor(model => model.ProductId)
@Html.LabelFor(model => model.ProductName)
@Html.EditorFor(model => model.ProductName)
@Html.ValidationMessageFor(model => model.ProductName, "*")
@Html.CheckBoxFor(model => model.HaveExperiance)
@Html.ValidationMessageFor(model => model.HaveExperiance, "*")
<input type="submit" value="Submit" />
}
</div>
So far i have tried the above code, Actually i needed when i click on checkbox then it should start validate my ProductName textbox, if uncheck then not. iam missing a little thing in above code, please help and rectify me.
Upvotes: 3
Views: 1623
Reputation: 2936
This is a complete example of how to create a custom validation attribute based on another attribute:
public class RequiredIfAttribute : ValidationAttribute
{
private RequiredAttribute _innerAttribute = new RequiredAttribute();
public string Property { get; set; }
public object Value { get; set; }
public RequiredIfAttribute(string typeProperty) {
Property = typeProperty;
}
public RequiredIfAttribute(string typeProperty, object value)
{
Property = typeProperty;
Value = value;
}
public override bool IsValid(object value)
{
return _innerAttribute.IsValid(value);
}
}
public class RequiredIfValidator : DataAnnotationsModelValidator<RequiredIfAttribute>
{
public RequiredIfValidator(ModelMetadata metadata, ControllerContext context, RequiredIfAttribute attribute) : base(metadata, context, attribute) { }
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
return base.GetClientValidationRules();
}
public override IEnumerable<ModelValidationResult> Validate(object container)
{
PropertyInfo field = Metadata.ContainerType.GetProperty(Attribute.Property);
if (field != null) {
var value = field.GetValue(container, null);
if ((value != null && Attribute.Value == null) || (value != null && value.Equals(Attribute.Value))) {
if (!Attribute.IsValid(Metadata.Model)) {
yield return new ModelValidationResult { Message = ErrorMessage };
}
}
}
}
}
In Global.asax
file in Application_Start
add this part:
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(RequiredIfAttribute), typeof(RequiredIfValidator));
This part is needed to registate the RequiredIfValidator
otherwise MVC will use only RequiredIfAttribute
ignoring RequiredIfValidator
.
If you want to validate ProductName
if HaveExperiance
have a value:
[RequiredIf("HaveExperiance")]
public string ProductName { get; set; }
If you want to validate ProductName
only if HaveExperiance
is false:
[RequiredIf("HaveExperiance", false)]
public string ProductName { get; set; }
If you want to validate ProductName
only if HaveExperiance
is true:
[RequiredIf("HaveExperiance", true)]
public string ProductName { get; set; }
In RequiredIfAttribute
class I created a RequiredAttribute
object only to validate the value passed to IsValid
method.
Property
field is used to save the name of property that activate the validation. It is used in class RequiredIfValidator
to get the field current value using reflection (field.GetValue(container, null)
).
When you call validation in your code (for example when you do if(TryValidateModel(model))
) first you call RequiredIfValidator
class that then call RequiredIfAttribute
(through Attribute.IsValid(Metadata.Model)
) class if some conditions are valid ((value != null && Attribute.Value == null) || (value != null && value.Equals(Attribute.Value))
).
One last thing. Because RequiredIfAttribute
inherits from ValidationAttribute
you can also use error messages in the same way of any other validation attribute.
[RequiredIf("HaveExperiance", true, ErrorMessage = "The error message")]
public string ProductName { get; set; }
[RequiredIf("HaveExperiance", true, ErrorMessageResourceName = "ResourceName", ErrorMessageResourceType = typeof(YourResourceType))]
public string ProductName { get; set; }
Upvotes: 5