Dynamic Validation in ASP MVC

For a project at work, I am trying to create a process that allows the user to dynamically create a form that other users could fill in values โ€‹โ€‹for. I am having trouble figuring out how to get this to play well with the built-in snapping and model validation using ASP MVC 3. However.

Our view model is set up like this. Note that I have simplified the example code:

public class Form 
{
    public FieldValue[] FieldValues { get; set; }
}

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

public class FieldValue 
{
    public Field Field { get; set; }
    public string Value { get; set; }
}

And our view looks something like this:

@model Form
@using (Html.BeginForm("Create", "Form", FormMethod.Post))
{
    @for(var i = 0; i < Model.Fields.Count(); i++)
    {
        @Html.TextBoxFor(_ => @Model.Fields[i].Value) 
    }
    <input type="submit" value="Save" name="Submit" />
}

, ModelValidatorProvider ModelMetadataProvider, FieldValue, , Field.IsRequired, RequiredFieldValidator , . , ModelValidatorProvider ( ModelMetadataProvider) ( : GetValidators() FieldValue.Value, , FieldValue).

, :

  • ModelValidatorProvider ControllerContext.Controller.ViewData.Model, , . Form.FieldValues โ€‹โ€‹[3], , FieldValue .

  • ModelMetadata, modelAccessor Target, , , . - MVC, , , , Target (), FieldValue. , , , FieldValue .

  • , FieldValue , . .

MVC? -, ?

+3
1

.

, . IsRequired . , , . , , , ( , ), - ( ...). . = > , , , , , .

, , IsRequired. , :

:

public class Form
{
    public FieldValue[] Fields { get; set; }
}

public class FieldValue
{
    public Field Field { get; set; }

    [ConditionalRequired("Field")]
    public string Value { get; set; }
}

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

:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new Form
        {
            Fields = new[]
            {
                new FieldValue { Field = new Field { IsRequired = true }, Value = "" },
                new FieldValue { Field = new Field { IsRequired = true }, Value = "" },
                new FieldValue { Field = new Field { IsRequired = false }, Value = "value 3" },
            }
        };
        return View(model);
    }

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

:

@model Form
@using (Html.BeginForm())
{
    @Html.EditorFor(x => x.Fields)
    <input type="submit" value="Save" name="Submit" />
}

ConditionalRequiredAttribute:

public class ConditionalRequiredAttribute : ValidationAttribute, IClientValidatable
{
    private RequiredAttribute _innerAttribute = new RequiredAttribute();

    private readonly string _fieldProperty;

    public ConditionalRequiredAttribute(string fieldProperty)
    {
        _fieldProperty = fieldProperty;
    }

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

        var fieldValue = (Field)field.GetValue(validationContext.ObjectInstance, null);
        if (fieldValue == null)
        {
            return new ValidationResult(string.Format("The property {0} was null", _fieldProperty));
        }

        if (fieldValue.IsRequired && !_innerAttribute.IsValid(value))
        {
            return new ValidationResult(this.ErrorMessage, new[] { validationContext.MemberName });
        }

        return ValidationResult.Success;
    }


    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule()
        {
            ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
            ValidationType = "conditionalrequired",
        };

        rule.ValidationParameters.Add("iserquiredproperty", _fieldProperty + ".IsRequired");

        yield return rule;
    }
}

:

(function ($) {
    $.validator.unobtrusive.adapters.add('conditionalrequired', ['iserquiredproperty'], function (options) {
        options.rules['conditionalrequired'] = options.params;
        if (options.message) {
            options.messages['conditionalrequired'] = options.message;
        }
    });

    $.validator.addMethod('conditionalrequired', function (value, element, parameters) {
        var name = $(element).attr('name'),
        prefix = name.substr(0, name.lastIndexOf('.') + 1),
        isRequiredFiledName = prefix + parameters.iserquiredproperty,
        requiredElement = $(':hidden[name="' + isRequiredFiledName + '"]'),
        isRequired = requiredElement.val().toLowerCase() === 'true';

        if (!isRequired) {
            return true;
        }

        return value && value !== '';
    });

})(jQuery);
0

All Articles