如何在Razor ASP.NET Core中实现条件必填属性的客户端验证
解决方案
一、修复下拉框提交后丢失选中值问题
下拉框值丢失的核心原因是OnPostAsync方法中重新生成SelectList时没有指定选中值,ASP.NET Core渲染下拉框时会默认选中空选项。
修复步骤:
- 修改
OnPostAsync中所有SelectList的初始化逻辑,增加第四个参数传入当前提交的选中值:
if (!ModelState.IsValid) { // 所有SelectList构造方法末尾增加选中值参数 ViewData["EntityID"] = new SelectList(_context.Entity.Where(a => a.Active == "Y").OrderBy(a => a.Name), "ID", "Name", SecurityLog.EntityID); ViewData["ShiftRangeID"] = new SelectList(_context.ShiftRange.Where(a => a.Active == "Y").OrderBy(a => a.Name), "ID", "Name", SecurityLog.ShiftRangeID); ViewData["LocationID"] = new SelectList(_context.Location.Where(a => a.Active == "Y" && a.EntityID == SecurityLog.EntityID).OrderBy(a => a.Name), "ID", "Name", SecurityLog.LocationID); ViewData["EventTypeID"] = new SelectList(_context.EventType.Where(a => a.Active == "Y").OrderBy(a => a.Name), "ID", "Name", SecurityLog.EventTypeID); return Page(); }
- 级联下拉框(Location)补充回发后自动选中逻辑,在页面底部加如下JS:
$(function(){ // 页面加载时如果Entity已经有值,自动加载对应Location并选中 var entityId = $('#entity').val(); if(entityId){ $.getJSON('?handler=Locations&entity=' + entityId, function(data){ var locationSelect = $('#location'); locationSelect.empty(); locationSelect.append('<option value="">--Select Location--</option>'); $.each(data, function(index, item){ locationSelect.append($('<option></option>').attr('value', item.value).text(item.text)); }); // 设置之前选中的Location值 locationSelect.val('@Model.SecurityLog.LocationID'); }); } });
二、实现RequiredIf属性的客户端验证
第一步:修改自定义验证属性,实现客户端验证适配
让RequiredIfAttribute继承IClientModelValidator接口,生成客户端验证需要的data-*属性:
public class RequiredIfAttribute : ValidationAttribute, IClientModelValidator { public string PropertyName { get; set; } public object Value { get; set; } public RequiredIfAttribute(string propertyName, object value, string errorMessage = "") { PropertyName = propertyName; ErrorMessage = errorMessage; Value = value; } protected override ValidationResult IsValid(object value, ValidationContext validationContext) { var instance = validationContext.ObjectInstance; var type = instance.GetType(); var proprtyvalue = type.GetProperty(PropertyName).GetValue(instance, null); if (proprtyvalue?.ToString() == Value.ToString() && value == null) { return new ValidationResult(ErrorMessage); } return ValidationResult.Success; } // 新增客户端验证适配方法 public void AddValidation(ClientModelValidationContext context) { MergeAttribute(context.Attributes, "data-val", "true"); MergeAttribute(context.Attributes, "data-val-requiredif", ErrorMessage); MergeAttribute(context.Attributes, "data-val-requiredif-property", PropertyName); MergeAttribute(context.Attributes, "data-val-requiredif-value", Value.ToString()); } private bool MergeAttribute(IDictionary<string, string> attributes, string key, string value) { if (attributes.ContainsKey(key)) { return false; } attributes.Add(key, value); return true; } }
第二步:页面增加AppType隐藏域
在Security Log创建页的表单内增加隐藏域,让客户端能获取到AppType的值:
<input type="hidden" asp-for="SecurityLog.AppType" value="Security Log" />
第三步:添加客户端验证逻辑
确保页面已经引用了jquery.validate.js和jquery.validate.unobtrusive.js,然后添加如下JS代码:
// 新增requiredif验证规则 $.validator.addMethod("requiredif", function (value, element, parameters) { var targetProperty = $('[name="' + parameters.dependentProperty + '"]'); var targetValue = parameters.targetValue; // 如果依赖属性的值等于目标值,则当前字段必填 if (targetProperty.val() == targetValue) { return $.trim(value) != ''; } return true; }); // 适配unobtrusive验证 $.validator.unobtrusive.adapters.add("requiredif", ["property", "value"], function (options) { options.rules["requiredif"] = { dependentProperty: options.params.property, targetValue: options.params.value }; options.messages["requiredif"] = options.message; });
内容的提问来源于stack exchange,提问作者Rob C
相关产品推荐
相关产品推荐

