简体   繁体   English

万无一失的MVC 5降级验证

[英]Foolproof MVC 5 deppending validation

Grettings my friends... 问候我的朋友们...

So i have a set of CheckBoxes that i set in my model: 因此,我在模型中设置了一组CheckBoxes:

    [DisplayName("Páginas Consultadas")]
    public List<CheckBoxes> PaginasConsultadas { get; set; }

And i have a fieldtext ("ParaQueUsaEstasPag") that is only required if any of checkboxes its checked... 而且我有一个fieldtext(“ ParaQueUsaEstasPag”),仅当其复选框中的任何一个选中时才需要...

    [DisplayName("¿Para que usa esta(s) página(s)?")]
    public string ParaQueUsaEstasPag { get; set; }

And part of the view: 部分视图:

    <div class="col-lg-4" id="DivPagConsultadas">
        <span>@Html.LabelFor(model => model.PaginasConsultadas, @Html.DisplayNameFor(model => model.PaginasConsultadas))</span>
        @{

    for (int i = 0; i < Model.PaginasConsultadas.Count(); i++)
    {
        <div class="checkbox">
            <label>
                @Html.CheckBoxFor(model => model.PaginasConsultadas[i].ValorCheckBox) @Model.PaginasConsultadas[i].NombreCheckBox
            </label>
        </div>
            @Html.HiddenFor(model => model.PaginasConsultadas[i].valorRespuesta, new { @Value = @Model.PaginasConsultadas[i].valorRespuesta })
    }

        }
    </div>
</div>
<br />
<div class="row">
    <div class="col-lg-12">

        @Html.LabelFor(model => model.ParaQueUsaEstasPag, @Html.DisplayNameFor(model => model.ParaQueUsaEstasPag))
        @Html.TextAreaFor(model => model.ParaQueUsaEstasPag, 5, 1, new { @class = "form-control", placeholder = "Esta pregunta se responde con base en la respuesta de la pregunta anterior" })
        @Html.ValidationMessageFor(model => model.ParaQueUsaEstasPag)
    </div>
</div>
    <br />
<div class="row">
    <div class="col-lg-12">
        <button type="submit" class="btn btn-default" onclick="dispararPleaseWait()">Enviar Encuesta...</button>
    </div>
</div>

There's is a mode to do this using Foolproof (ie [RequiredIf])? 有一种使用万无一失的方式来做到这一点(即[RequiredIf])吗?


Update: Follow the Elad idea, my class is the next: 更新:遵循Elad的想法,下一节是我的课:

public class PagSeleccionadasValidation : ValidationAttribute, IClientValidatable
{
    //todo
    private readonly String _ChkPagSel;

    public PagSeleccionadasValidation(String ChkPagSel)
    {
        _ChkPagSel = ChkPagSel;
    }

    public string P {get; set;}
    protected override ValidationResult IsValid(object value, ValidationContext validationcontext)
    {
        if (value == null)
        {
            var PropertyInfo = validationcontext.ObjectType.GetProperty(_ChkPagSel);
            var Lista = (List<CheckBoxes>)PropertyInfo.GetValue(validationcontext.ObjectInstance, null);
            bool HayAlgunaCheck = Lista.Any(r => r.ValorCheckBox == true);
            if (HayAlgunaCheck)
            {
                return new ValidationResult(this.ErrorMessageString);
            }
            else
            {
                return ValidationResult.Success;
            }
        }
        return ValidationResult.Success;           
    }
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {

        var rule = new ModelClientValidationRule
        {
            ErrorMessage = FormatErrorMessage(metadata.DisplayName),
            ValidationType = "valpagselecc"
        };
        rule.ValidationParameters["valpag"] = P;

        yield return rule;

    }

}

In the js called "JS-ValPagSel.js" i put this: 在名为“ JS-ValPagSel.js”的js中,我这样写:

$.validator.unobtrusive.adapters.addSingleVal('valpagselecc', 'valpag');

$.validator.addMethod('valpagselecc', function (value, element, params) {
//var checkValue = [Find element via jquery from the params.checkpropertinputname];
if (value) {
    return false; // just for test
}
else {
    return false;
}

}); });

And in the view: 并在视图中:

<script src="/Scripts/jquery-1.10.2.js"></script>
<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.min.js"></script>
<script src="/Scripts/bootstrap.js"></script>
<script src="/Scripts/respond.js"></script>
<script src="/Scripts/blur.js"></script>
<script src="/Scripts/jquery-ui-1.11.1.js"></script>
<script src="/Scripts/jquery.validate.js"></script>
<script src="/Scripts/jquery.validate.unobtrusive.js"></script>
<script src="/Scripts/Custom/JS-ValPagSel.js"></script>

<textarea class="form-control" cols="1" data-val="true" data-val-valpagselecc="El campo ¿Para que usa esta(s) página(s)? no es válido." data-val-valpagselecc-valpag="" id="ParaQueUsaEstasPag" name="ParaQueUsaEstasPag" placeholder="Esta pregunta se responde con base en la respuesta de la pregunta anterior" rows="5"></textarea>

In Foolproof you have those options for [RequiredIf(...)]: 在万无一失中,您可以使用[RequiredIf(...)]的那些选项:

[RequiredIf]
[RequiredIfNot]
[RequiredIfTrue]
[RequiredIfFalse]
[RequiredIfEmpty]
[RequiredIfNotEmpty]
[RequiredIfRegExMatch]
[RequiredIfNotRegExMatch]

In your case "Checkboxes" is a class, custom made, i suppose. 我想在您的情况下,“复选框”是定制的类。 You'll have to create a custom Attribute to validate this 您必须创建一个自定义属性来对此进行验证

OR... 要么...

You could add a Property on this class to return a boolean and use the RequiredIfTrue validator. 您可以在此类上添加一个Property以返回布尔值并使用RequiredIfTrue验证器。

public class Checkboxes {
    public bool IsAtLeastOneSelected
    {
        get{
            return PaginasConsultadas.Any(r => r.ValorCheckBox == [WHATEVER_VALUE MEANS_CHECKED]);
        }
    }
}

and then... 接着...

[RequiredIfTrue("IsAtLeastOneSelected")]
[DisplayName("¿Para que usa esta(s) página(s)?")]
public string ParaQueUsaEstasPag { get; set; }

Your ViewModel is probably like this: 您的ViewModel可能是这样的:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;

public class TestViewModel
{
    public List<Checkboxes> PaginasConsultadas { get; set; }

    [RequiredIfTrue("IsAtLeastOneSelected")]
    public string ParaQueUsaEstasPag { get; set; }

    //You dont put that on your view. 
    //This is just used with RequiredIfTrue data anotation attribute so the Validator checks for it
    public bool IsAtLeastOneSelected
    {
        get { return PaginasConsultadas.Any(r => r.ValorCheckBox); }
    }
}

public class Checkboxes
{
    //In order to check/uncheck you should use boolean for ValorCheckBox
    public bool ValorCheckBox { set; get; }
    public string NombreCheckBox { set; get; }
}

The rest, [Foolproof configuration] you've got to check the documentation. 剩下的,[万无一失的配置],您必须检查文档。 There are some scripts you have to add to make it work. 您必须添加一些脚本才能使其正常运行。

http://foolproof.codeplex.com/ RequireIf Code = http://foolproof.codeplex.com/SourceControl/latest#Foolproof/RequiredIf.cs http://foolproof.codeplex.com/ RequireIf代码= http://foolproof.codeplex.com/SourceControl/latest#Foolproof/RequiredIf.cs

What I would do is make the field [Required] and in your action check if one of the checkboxes is checked. 我要做的是在[Required]字段中进行action检查是否选中了其中一​​个复选框。 If not, you can remove the specific required error from the ModelState before checking ModelState.IsValid . 如果不是,则可以在检查ModelState.IsValid之前从ModelState删除特定的必需错误。

Example: 例:

if (Model.MyCheckBox.Checked)
{
   ModelState.Remove("CheckboxName");
}

if(ModelState.IsValid)
{
   //Do stuff...
}

Since you require client-side validation as well, I will add another option. 由于您还需要客户端验证,因此我将添加另一个选项。 You can use a custom data annotation. 您可以使用自定义数据注释。 You need to create a class that inherits from ValidationAttribute and implements IClientValidatable . 您需要创建一个从ValidationAttribute继承并实现IClientValidatable

public class RequiredIf : ValidationAttribute, IClientValidatable
{
    private string _checkPropertyName;

    public RequiredIf(string checkPropertyName)
    {
        _checkPropertyName = checkPropertyName;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        //Get PropertyInfo object
        var phonePropertyInfo = validationContext.ObjectType.GetProperty(_checkPropertyName);

        //Get value from property
        bool checkValue = (bool)phonePropertyInfo.GetValue(validationContext.ObjectInstance, null);

        if(!checkValue)
           return new ValidationResult(this.ErrorMessageString);

        return null;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        ModelClientValidationRule rule = new ModelClientValidationRule();
        rule.ErrorMessage = this.ErrorMessageString;
        rule.ValidationType = "requiredIf";

        rule.ValidationParameters.Add("checkpropertinputname", _checkPropertyName);

        yield return rule;
    }
}

This is a simplified example, but you can work along these lines. 这是一个简化的示例,但是您可以按照以下说明进行操作。 You can pass in to the constructor anything you like and pull all the data from the model via reflection, as in the example. 您可以将任何您喜欢的内容传递给构造函数,并通过反射从模型中提取所有数据,如示例中所示。

On the client side you need JS along these lines: 在客户端,您需要遵循以下几条JS:

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

$.validator.addMethod('requiredIf', function (value, element, params) {
    var checkValue = *[Find element via jquery from the params.checkpropertinputname]*;

});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM