【问题标题】:Custom Attribute Validation: make field required based on selected option自定义属性验证:根据所选选项制作必填字段
【发布时间】:2019-03-07 13:45:46
【问题描述】:

如果从select 中选择了特定的option,我正在尝试设置一个必填字段。

到目前为止我所拥有的:

视图模型:

public enum RequestType
{
    PaidLeaveOfAbsence = 1,
    WorkFromHome = 2,
    SickLeave = 3,
    BriefLeaveOfAbsence = 4
}

public class RequestFormViewModel
{
    public RequestType SelectedRequestType { get; set; }

    public DateTime FromDate { get; set; }

    public DateTime ToDate { get; set; }

    [RequieredIf("SelectedRequestType")]
    public string Comment { get; set; }
}

自定义属性:

public class RequieredIfAttribute : ValidationAttribute, IClientModelValidator
{
    private readonly string _otherProperty;

    public RequieredIfAttribute(string otherProperty)
    {
        _otherProperty = otherProperty;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        string comment = (string)value;

        RequestType selectedRequestType = (RequestType)validationContext.ObjectType.GetProperty(_otherProperty).GetValue(validationContext.ObjectInstance, null);

        if (string.IsNullOrEmpty(comment) && selectedRequestType == RequestType.BriefLeaveOfAbsence)
        {
            return new ValidationResult("Comment is requiered.");
        }

        return ValidationResult.Success;
    }

    public void AddValidation(ClientModelValidationContext context)
    {
        MergeAttribute(context.Attributes, "data-val", "true");
        MergeAttribute(context.Attributes, "data-val-required-if", "Comment is requiered.");
        MergeAttribute(context.Attributes, "data-val-other", "#" + _otherProperty);
    }

    private static bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
    {
        if (attributes.ContainsKey(key))
        {
            return false;
        }
        attributes.Add(key, value);
        return true;
    }
}

HTML:

<div class="row">
<div class="col-0 col-md-2"></div>
<div class="col-12 col-md-4">
    <form asp-action="Create">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-group">
            <label asp-for="SelectedRequestType" class="control-label"></label>
            <select asp-for="SelectedRequestType" asp-items="Html.GetEnumSelectList<RequestType>()" class="form-control">
                <option selected="selected" value="">Select a request</option>
            </select>
            <span asp-validation-for="SelectedRequestType" class="text-danger"></span>
        </div>
        <div class="form-group">
            <label asp-for="FromDate" class="control-label"></label>
            <input asp-for="FromDate" class="form-control" type="text" value="" id="fromDate" autocomplete="off" />
            <span asp-validation-for="FromDate" class="text-danger"></span>
        </div>
        <div class="form-group">
            <label asp-for="ToDate" class="control-label"></label>
            <input asp-for="ToDate" class="form-control" type="text" value="" id="toDate" autocomplete="off" />
            <span asp-validation-for="ToDate" class="text-danger"></span>
        </div>
        <div class="form-group">
            <input type="submit" value="Create" class="btn btn-primary" />
        </div>
    </form>
</div>
<div class="col-12 col-md-4">
    <div class="form-group">
        <label asp-for="Comment" class="control-label">Comment</label>
        <textarea asp-for="Comment" class="form-control" id="comment" rows="3"></textarea>
        <span asp-validation-for="Comment" class="text-danger"></span>
    </div>
</div>
<div class="col-0 col-md-2"></div>

生成的 HTML:

<select class="form-control" data-val="true" id="SelectedRequestType" name="SelectedRequestType">
    <option selected="selected" value="">Select a request</option>
    <option value="1">PaidLeaveOfAbsence</option>
    <option value="2">WorkFromHom</option>
    <option value="3">SickLeave</option>
    <option value="4">BriefLeaveOfAbsence</option>
</select>
...
<div class="form-group">
    <label class="control-label" for="Comment">Comment</label>
    <textarea class="form-control" id="comment" rows="3" data-val="true" data-val-other="#SelectedRequestType" data-val-required-if="Comment is required." name="Comment"></textarea>
    <span class="text-danger field-validation-valid" data-valmsg-for="Comment" data-valmsg-replace="true"></span>
</div>

服务器端验证工作正常。我一直在添加客户端验证,到目前为止我有这个:

validator.js

jQuery.validator.addMethod("required-if",
    function (value, element, param) {
        var otherProp = $($(element).data('val-other'));
        console.log(otherProp);
        if (!value.trim() && otherProp.val() == 4) {
            return false;
        }
        return true;
    }
)

jQuery.validator.unobtrusive.adapters.add("required-if", ["other"], 
    function (options) {
        console.log(options);
        options.rules["required-if"] = "#" + options.params.other;
        options.messages["required-if"] = options.message;
});

我已经放了一些console.log()s,但它们从未被执行。 (我确实保留了 chrome 中的日志)。

大部分谷歌搜索来自实现IClientValidatable 接口的ASP.NET MVC,并不是很有用。我正在使用 ASP.NET Core 2.2.0。

我确实阅读了 microsoft docslink 他们为不寻常的验证器提供的自定义适配器。

问题:

  1. 我怎样才能以这种方式实现预期的行为?我做错了什么,我该如何解决?

  2. 我还有哪些其他选择?我应该使用 jQuery 验证插件进行单独的客户端验证吗?我不喜欢在 2 个不同的地方进行验证的想法。

  3. 有人可以向我解释为什么 JavaScript 函数中的 console.log()s 永远不会执行吗?我有FromDateToDate 的自定义验证器,它们在那里执行。唯一的区别是我使用 jQuery.validator.unobtrusive.adapters.addBool 而不是 jQuery.validator.unobtrusive.adapters.add

【问题讨论】:

    标签: javascript c# jquery asp.net-core-mvc unobtrusive-validation


    【解决方案1】:

    您可以让您的 FormViewModel 扩展 IValidatableObject。一旦你这样做,实现 Validate 方法。在那里,您可以根据模型中的值进行自定义验证。比如:

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if(SelectedRequestType == RequestType.PaidLeaveOfAbsence) 
            {
                // Check if field is not null and return
                yield return new ValidationResult(
                "SomeField should be present.",
                new[] { "SomeField" });
            }
        }
    

    您可以使用pattern matching 使上述语法更优雅

    你可以在link找到更多关于模型验证的信息

    【讨论】:

    • 我看不出这与客户端验证有什么关系。你能详细说明一下吗?正如我在帖子中提到的,我已经阅读了 microsoft 文档(您提供的链接)。
    【解决方案2】:

    comment 部分位于form 之外,因此永远不会进行验证。 答案在我原帖的link 中找到。

    重要提示:jQuery Validate 要求您的输入元素是 在&lt;form&gt; 元素内进行验证。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-07-10
      • 2016-06-12
      • 2016-09-07
      • 2023-03-15
      • 2022-11-22
      • 1970-01-01
      • 2020-02-27
      相关资源
      最近更新 更多