2

In my program, for an entity, I have a Save and a Submit button. For my entity, I have a field that determines whether of not another field is required. An example of such a scenario:

public class Question{
bool IsRequired {get; set;}
string Answer {get; set;}
}

I know that I can make a custom validation attribute to make Answer required based on the IsRequired field, but the problem is, I only want this validation when the user "submits" the form, and not just saves it.
What's the best approach to validate the entity server side? I'm thinking about either making a IsValid method in my service class and returning a list of errors, and then adding then to the ModelState in the controller. Or, maybe using the custom validation attribute and do it client side and somehow disable validation when the save is clicked, and enable it for the submit button. It seems like there should be a more elegant solution to this. Does anyone have any suggestions?

Edit: Here's the code I'm using for my attribute:

 public class RequiredIfAttribute : ValidationAttribute
    {

        RequiredAttribute _innerAttribute = new RequiredAttribute();
        private string _dependentProperty { get; set; }
        private object _targetValue { get; set; }

        public RequiredIfAttribute(string dependentProperty, object targetValue)
        {
            this._dependentProperty = dependentProperty;
            this._targetValue = targetValue;
        }
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            var field = validationContext.ObjectType.GetProperty(_dependentProperty);
            if (field != null)
            {
                var dependentValue = field.GetValue(validationContext.ObjectInstance, null);
                if ((dependentValue == null && _targetValue == null) || (dependentValue.Equals(_targetValue)))
                {
                    if (!_innerAttribute.IsValid(value))
                    {
                        string name = validationContext.DisplayName;
                        return new ValidationResult(ErrorMessage = name + " Is required.");
                    }
                }
                return ValidationResult.Success;
            }
            else
            {
                return new ValidationResult(FormatErrorMessage(_dependentProperty));
            }
        }

    }

The controller method:

 public ActionResult FormDetail(UserFormDTO model, string buttonType)
    {
        if (buttonType == "Save")
        {                
            if (!ModelState.IsValid)
            {
                return FormDetail(model.UserFormID);
            }

           //Save code is here                
        }
        else if (buttonType == "Submit")
        {
            if (!ModelState.IsValid)
            {
                return FormDetail(model.UserFormID);
            }

           //Submit code is here
        }

        return RedirectToAction("Forms");
    }

UserFormDTO has a list of Questions.

user568551
  • 337
  • 3
  • 11
  • Your editing data so always use a view model. Tour view model will have the `[ RequiredIf]` attribute. –  Dec 24 '17 at 22:54
  • 2
    Possible duplicate of [Conditionally required property using data annotations](https://stackoverflow.com/questions/26354853/conditionally-required-property-using-data-annotations) – Fakhar Ahmad Rasul Dec 24 '17 at 23:59
  • I have looked into using the custom data annotation, but how would I keep it from validating if the save button is click, but validate if the submit button is clicked? – user568551 Dec 25 '17 at 02:50

1 Answers1

6

To suit your current design, i.e. to determine if Answer is mandatory base on the IsRequired, you need to set the IsRequired value base on the button clicked. here is one way to do it:

<button name="IsRequired" value="false">Save</button>
<button name="IsRequired" value="true">Submit</button>

EDIT Update the Question class to use the RequiredIf attribute to validate the model. Note, RequiredIf comes by way of the MVC Foolproof Validation package.

public class Question
{
    public bool IsRequired { get; set; }

    [RequiredIf("IsRequired", true)]
    public string Answer { get; set; }
}

Also, by convention, the name of the attribute class should end with 'Attribute' to increase code readability, so it's better to change the RequiredIf class name to RequireIfAttribute

public class RequiredIfAttribute : ValidationAttribute

You don't have to include the Attribute suffix when applying the attribute in your model(as the above code shown), the compile can recogize the attribute class.

Mike Wright
  • 502
  • 4
  • 13
Evan Huang
  • 1,245
  • 9
  • 16