自定义属性验证:根据所选选项制作必填字段
Custom Attribute Validation: make field required based on selected option
如果从 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()
,但它们从未执行过。 (我确实在 chrome 中保留了日志)。
大多数 google 搜索来自实现 IClientValidatable
接口的 ASP.NET MVC,不是很有用。我正在使用 ASP.NET Core 2.2.0.
我确实阅读了微软 docs and the link 他们为不寻常的验证器提供的自定义适配器。
问题:
如何通过这种方式实现预期的行为?我做错了什么,我该如何解决?
我还有哪些其他选择?我是否应该使用 jQuery 验证插件进行单独的客户端验证?我不喜欢在两个不同的地方进行验证的想法。
有人可以向我解释为什么 javascript 函数中的 console.log()
永远不会执行吗?我有 FromDate
和 ToDate
的自定义验证器,它们在那里执行。唯一的区别是我使用
jQuery.validator.unobtrusive.adapters.addBool
而不是 jQuery.validator.unobtrusive.adapters.add
.
您可以让 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
找到有关模型验证的更多信息
comment
部分在 form
之外,因此永远不会进行验证。
答案在我原来的 post.
中的 link 中找到
Important note: jQuery Validate requires your input elements to be
inside of a <form>
element in order to be validated.
如果从 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()
,但它们从未执行过。 (我确实在 chrome 中保留了日志)。
大多数 google 搜索来自实现 IClientValidatable
接口的 ASP.NET MVC,不是很有用。我正在使用 ASP.NET Core 2.2.0.
我确实阅读了微软 docs and the link 他们为不寻常的验证器提供的自定义适配器。
问题:
如何通过这种方式实现预期的行为?我做错了什么,我该如何解决?
我还有哪些其他选择?我是否应该使用 jQuery 验证插件进行单独的客户端验证?我不喜欢在两个不同的地方进行验证的想法。
有人可以向我解释为什么 javascript 函数中的
console.log()
永远不会执行吗?我有FromDate
和ToDate
的自定义验证器,它们在那里执行。唯一的区别是我使用jQuery.validator.unobtrusive.adapters.addBool
而不是jQuery.validator.unobtrusive.adapters.add
.
您可以让 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
找到有关模型验证的更多信息comment
部分在 form
之外,因此永远不会进行验证。
答案在我原来的 post.
Important note: jQuery Validate requires your input elements to be inside of a
<form>
element in order to be validated.