C# 如何在列表中的每个项目的属性上添加客户端不引人注目的验证,并一次性打印消息?
我有一个视图模型:C# 如何在列表中的每个项目的属性上添加客户端不引人注目的验证,并一次性打印消息?,c#,jquery,asp.net-mvc,validation,unobtrusive-validation,C#,Jquery,Asp.net Mvc,Validation,Unobtrusive Validation,我有一个视图模型: public class RatingsEditViewModel { [PropertyOnEveryItemInListRequired(Common.TranslationsEnums.DetailObjectRating.ValidationMessageRateEveryParameter, "Rating")] public List<ReviewCategoryViewModel> CategoryTypes { get; set;
public class RatingsEditViewModel
{
[PropertyOnEveryItemInListRequired(Common.TranslationsEnums.DetailObjectRating.ValidationMessageRateEveryParameter, "Rating")]
public List<ReviewCategoryViewModel> CategoryTypes { get; set; }
= new List<ReviewCategoryViewModel>();
}
我创建了一个自定义属性和适配器来验证服务器端,如下所示:
public class PropertyOnEveryItemInListRequiredAttribute : RequiredAttribute
{
private string errorMessage;
private string propertyName;
public PropertyOnEveryItemInListRequiredAttribute(int id, string propertyName)
{
this.errorMessage = Translations.Translator.GetTranslation(id);
this.propertyName = propertyName;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
ModelClientValidationRule propertyOnEveryItemInListRequiredAttribute = new ModelClientValidationRule();
propertyOnEveryItemInListRequiredAttribute.ErrorMessage = this.errorMessage;
propertyOnEveryItemInListRequiredAttribute.ValidationType = "propertyoneveryiteminlistrequiredattribute";
yield return propertyOnEveryItemInListRequiredAttribute;
}
public override bool IsValid(object value)
{
var list = value as IList;
if (list != null)
{
foreach (var element in list)
{
var property = element.GetType().GetProperty(this.propertyName);
if (property.PropertyType == typeof(int))
{
var intValue = (int)property.GetValue(element, null);
if (intValue == 0)
{
return false;
}
else
{
continue;
}
}
}
return true;
}
return false;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
return this.IsValid(value) ? ValidationResult.Success : new ValidationResult(this.errorMessage);
}
}
public class PropertyOnEveryItemInListRequiredAttributeAdapter : DataAnnotationsModelValidator<PropertyOnEveryItemInListRequiredAttribute>
{
public PropertyOnEveryItemInListRequiredAttributeAdapter(ModelMetadata metadata, ControllerContext context, PropertyOnEveryItemInListRequiredAttribute attribute)
: base(metadata, context, attribute)
{
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
return this.Attribute.GetClientValidationRules(this.Metadata, this.ControllerContext);
}
}
我知道这可能不是最好的解决方案(看起来很糟糕),所以请随时发表评论
我已经在js中将该方法添加到validator中(它是一个虚拟的):
我需要验证用户在所有类别上的输入(他需要选择一个星(每个元素的评级值),但是如果他没有这样做,我只需要为整个列表编写一次验证消息,附加在所有类别的控件之后
未激发GetClientValidationRules,未填充data val属性,也未调用adapters的addMethod。是否有方法在不引人注目的验证中处理此问题?如果没有,处理此列表的客户端验证的最佳方法是什么?是否将验证属性应用于复杂属性(
CategoryTypes
)但您的视图不会为CategoryTypes
(也不应该)生成表单控件,因此无法获得客户端验证。为什么不在int?Rating
(可空属性)上使用[必需]
属性@StephenMuecke我只需要查看整个列表的验证消息一次(如果未填写)附加到列表中。我想使用我为后端创建的自定义属性。您建议我如何使用plz处理这种情况?您不能使用此属性访问客户端jquery验证库。您可以始终创建自己的脚本,该脚本在表单中激发。submit()`事件,该事件检查是否有任何值无效,如果是,则在DOM中显示消息(并在评级的输入的事件的.keyup()
上删除该消息)
public class PropertyOnEveryItemInListRequiredAttribute : RequiredAttribute
{
private string errorMessage;
private string propertyName;
public PropertyOnEveryItemInListRequiredAttribute(int id, string propertyName)
{
this.errorMessage = Translations.Translator.GetTranslation(id);
this.propertyName = propertyName;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
ModelClientValidationRule propertyOnEveryItemInListRequiredAttribute = new ModelClientValidationRule();
propertyOnEveryItemInListRequiredAttribute.ErrorMessage = this.errorMessage;
propertyOnEveryItemInListRequiredAttribute.ValidationType = "propertyoneveryiteminlistrequiredattribute";
yield return propertyOnEveryItemInListRequiredAttribute;
}
public override bool IsValid(object value)
{
var list = value as IList;
if (list != null)
{
foreach (var element in list)
{
var property = element.GetType().GetProperty(this.propertyName);
if (property.PropertyType == typeof(int))
{
var intValue = (int)property.GetValue(element, null);
if (intValue == 0)
{
return false;
}
else
{
continue;
}
}
}
return true;
}
return false;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
return this.IsValid(value) ? ValidationResult.Success : new ValidationResult(this.errorMessage);
}
}
public class PropertyOnEveryItemInListRequiredAttributeAdapter : DataAnnotationsModelValidator<PropertyOnEveryItemInListRequiredAttribute>
{
public PropertyOnEveryItemInListRequiredAttributeAdapter(ModelMetadata metadata, ControllerContext context, PropertyOnEveryItemInListRequiredAttribute attribute)
: base(metadata, context, attribute)
{
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
return this.Attribute.GetClientValidationRules(this.Metadata, this.ControllerContext);
}
}
<div class="row evaluation-content modal-rating">
@{
for (var i = 0; i < Model.CategoryTypes.Count; i++)
{
<div class="col-xs-12 evaluation-row">
@Html.HiddenFor(Model => Model.CategoryTypes[@i].Id)
@Html.HiddenFor(Model => Model.CategoryTypes[@i].Name)
<span class="name">@Model.CategoryTypes[i].Name: *</span>
<div class="rating-control pull-right">
@{
for (var j = 10; j > 0; j--)
{
<span id="@j"><i class="fa fa-star"></i></span>
}
}
</div>
@Html.TextBoxFor(Model => Model.CategoryTypes[@i].Rating, new { @id = "rating-" + i.ToString(), @style = "visibility: hidden; width: 0; height: 0; margin: 0;" })
@*@Html.ValidationMessageFor(Model => Model.CategoryTypes[i].Rating)*@
</div>
}
}
@Html.ValidationMessageFor(model => model.CategoryTypes)
</div>
<input type="submit" class="btn btn-primary" id="submitButton" />
$("#submitButton").on("click", function () {
var evalContainer = $(".row .evaluation-content div.rating-control");
for (var i = 0, div; div = evalContainer[i]; i++) {
for (var j = 0, span; span = div.children[j]; j++) {
if (span.className === "active") {
$("#rating-" + i).val(span.id);
}
}
}
});
$.validator.addMethod("propertyoneveryiteminlistrequiredattribute", function (value, element, params) {
if (!isValueZero(value))
{
return true;
} else {
return false;
}
});
$.validator.unobtrusive.adapters.add("propertyoneveryiteminlistrequiredattribute", ["propertyoneveryiteminlistrequiredattribute"], function (options) {
options.rules["propertyoneveryiteminlistrequiredattribute"] = true;
options.messages["propertyoneveryiteminlistrequiredattribute"] = options.message;
});
function isValueZero(str) {
return parseInt(str) == 0;
}