【问题标题】:MVC3 unobtrusive validation group of inputsMVC3 不显眼的验证输入组
【发布时间】:2011-04-28 09:15:08
【问题描述】:

我需要验证 3 个或更多输入字段(至少需要一个)。例如,我有电子邮件、传真、电话。

我至少需要填写一个。我需要服务器和客户端“不显眼的验证”。请帮忙。我研究了“比较”方法并尝试修改它,但没有运气。请帮忙。 谢谢

【问题讨论】:

标签: asp.net-mvc asp.net-mvc-3


【解决方案1】:

你可以写一个自定义属性:

public class AtLeastOneRequiredAttribute : ValidationAttribute, IClientValidatable
{
    private readonly string[] _properties;
    public AtLeastOneRequiredAttribute(params string[] properties)
    {
        _properties = properties;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (_properties == null || _properties.Length < 1)
        {
            return null;
        }

        foreach (var property in _properties)
        {
            var propertyInfo = validationContext.ObjectType.GetProperty(property);
            if (propertyInfo == null)
            {
                return new ValidationResult(string.Format("unknown property {0}", property));
            }

            var propertyValue = propertyInfo.GetValue(validationContext.ObjectInstance, null);
            if (propertyValue is string && !string.IsNullOrEmpty(propertyValue as string))
            {
                return null;
            }

            if (propertyValue != null)
            {
                return null;
            }
        }

        return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule
        {
            ErrorMessage = ErrorMessage,
            ValidationType = "atleastonerequired"
        };
        rule.ValidationParameters["properties"] = string.Join(",", _properties);

        yield return rule;
    }
}

可用于装饰您的视图模型属性之一(如果验证失败,您希望突出显示的属性):

public class MyViewModel
{
    [AtLeastOneRequired("Email", "Fax", "Phone", ErrorMessage = "At least Email, Fax or Phone is required")]
    public string Email { get; set; }
    public string Fax { get; set; }
    public string Phone { get; set; }
}

然后是一个简单的控制器:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new MyViewModel();
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(MyViewModel model)
    {
        return View(model);
    }
}

呈现以下视图,该视图将负责定义自定义客户端验证器适配器:

@model MyViewModel

<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
<script type="text/javascript">
    jQuery.validator.unobtrusive.adapters.add(
        'atleastonerequired', ['properties'], function (options) {
            options.rules['atleastonerequired'] = options.params;
            options.messages['atleastonerequired'] = options.message;
        }
    );

    jQuery.validator.addMethod('atleastonerequired', function (value, element, params) {
        var properties = params.properties.split(',');
        var values = $.map(properties, function (property, index) {
            var val = $('#' + property).val();
            return val != '' ? val : null;
        });
        return values.length > 0;
    }, '');
</script>

@using (Html.BeginForm())
{
    @Html.ValidationSummary(false)

    <div>
        @Html.LabelFor(x => x.Email)
        @Html.EditorFor(x => x.Email)
    </div>

    <div>
        @Html.LabelFor(x => x.Fax)
        @Html.EditorFor(x => x.Fax)
    </div>

    <div>
        @Html.LabelFor(x => x.Phone)
        @Html.EditorFor(x => x.Phone)
    </div>

    <input type="submit" value="OK" />
}

当然,自定义适配器和验证器规则应该外部化到单独的 javascript 文件中,以避免脚本与标记混合。

【讨论】:

  • 这帮了大忙。谢谢!
  • 由于某种原因,客户端验证不会触发 :(.??
  • @Shane Km,ClientValidationEnabled 属性是否在 web.config 中设置为 true?还要确保您使用的是与 jquery 兼容的 jquery.validate 插件版本。有一个旧版本与 jQuery 1.5 不兼容。
  • 此处的验证仅附在电子邮件中。如果只输入传真或电话,验证如何触发?如果填写了传真然后删除,验证将不会触发。
  • 我不太确定在此处的示例中实现是如何工作的。我可以让它工作的唯一方法是在其中一个属性上方添加属性,例如[MultiFieldRequired(new string[3]{"Phone1", "Phone2", "Phone3"}, ErrorMessage ="Phone# required")] ------代码只接受一个数组。我不确定人们如何使用这些逗号分隔的字符串并使其正常工作。
【解决方案2】:

我花了超过 36 个小时为什么代码对我不起作用。最后,我发现在我的情况下,我不应该在这行代码中使用属性名称

[AtLeastOneRequired("Email", "Fax", "Phone", ErrorMessage = "At least Email, Fax or Phone is required")]

但我必须使用 HTMl 元素 ID 来代替属性名称,它就像魔术一样工作。

如果对某人有帮助,请在此处发布。

【讨论】:

    【解决方案3】:

    由于您使用的是 MVC 3,请查看 great video Brad Wilson 在 mvcConf 上发表的文章。创建客户端+服务器不显眼验证所需的一切都应有尽有

    【讨论】:

      【解决方案4】:

      @Darin Dimitrov 的解决方案可能是创建与不显眼的验证一起使用的自定义验证属性的标准。但是,使用自定义验证属性进行不显眼的验证有一些缺点,例如:

      • 自定义验证属性仅附加到一个属性,因此如果其他两个输入发生更改事件,客户端验证将不起作用。
      • 错误消息与 ValidationSummary 一起工作正常,但如果您想为整个组显示 1 条错误消息(我认为这是常态),这几乎是不可能的。
      • 为了避免第一个问题,我们可以为组中的每个元素添加自定义验证属性,这将导致另一个问题:我们必须验证组中的所有元素,而不是在第一个无效组元素处停止。当然,第二个问题 - 每个元素的单独错误消息 - 仍然存在。

      还有另一种处理输入组客户端验证的方法,使用 jquery 验证器 (https://jqueryvalidation.org/validate/#groups) 中的组设置。唯一的问题(也是一个大问题)是默认情况下不显眼的验证不支持 jquery 验证的组,所以我们必须自定义一点。

      虽然这个答案很难“不引人注目”,但在我看来,如果您的最终目标是在使用 Microsoft 不引人注目的验证器库时验证一组输入,那么尝试摆脱不必要的代码复杂性是值得的。

      首先,由于默认 jquery 验证器的组设置在 jquery 非侵入式验证器中不可用,我们必须覆盖非侵入式设置(参考。How can I customize the unobtrusive validation in ASP.NET MVC 3 to match my style?

      $("form").on('submit', function () {
          var form = this;
          var validator = $(this).data("validator");
      
          if (validator.settings && !validator.settings.submitHandler) {
              $.extend(true, validator.settings.rules, validationSettings.rules);
              $.extend(true, validator.settings.groups, validationSettings.groups);
              initGroups(validator);
      
              var fnErrorReplacement = validator.settings.errorPlacement;
              validator.settings.errorPlacement = function (error, element) {
                  validationSettings.errorPlacement(error, element, fnErrorReplacement, form);
              }
              validator.settings.submitHandler = formSubmitHandler;
          }
      });
      
      function formSubmitHandler(form) {
          form.submit();
      }
      

      之后,覆盖不显眼的验证器组、规则和 errorPlacement 设置。

      var validationSettings = {
      groups: {
          checkboxgroup: "Email Fax Phone"
      },
      rules: {
          Email: {
              required: function () {
                  return validateCheckboxGroup(["#Email", "#Fax", "#Phone"]);
              }
          },
          Fax: {
              required: function () {
                  return validateCheckboxGroup(["#Email", "#Fax", "#Phone"]);
              }
          },
          Phone: {
              required: function () {
                  return validateCheckboxGroup(["#Email", "#Fax", "#Phone"]);
              }
          }
      }
      ,
      errorPlacement: function (error, element, fnUnobtrusive, form) {
          switch (element.attr("name")) {
              case "Email":
              case "Fax":
              case "Phone":
                  onGroupError(error, "CheckBoxGroup", form);
                  break;
              default:
                  fnUnobtrusive(error, element);
                  break;
          }
      }
      }
      
      function validateCheckboxGroup(names) {
      var result = true;
      $.each(names, function (index, value) {
          if ($(value).is(":checked")) {
              result = false;
          }
      });
      return result;
      }
      

      由于unobtrusive validator没有实现jquery validator的groups设置,我们需要复用两个库中的两个函数:(1).split group names(复用jquery validator的代码)和(2) append error element without remove 'input-validation-error' 类(重用函数 onError 从不显眼的库)。

      function initGroups(validators) {
      validators.groups = {};
      $.each(validators.settings.groups,
          function (key, value) {
              if (typeof value === "string") {
                  value = value.split(/\s/);
              }
              $.each(value,
                  function (index, name) {
                      validators.groups[name] = key;
                  });
          });
      }
      
      function onGroupError(error, inputElementName, form) {
      var container = $(form).find("[data-valmsg-for='" + inputElementName + "']"),
      replaceAttrValue = container.attr("data-valmsg-replace"),
      replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
      
      container.removeClass("field-validation-valid").addClass("field-validation-error");
      error.data("unobtrusiveContainer", container);
      
      if (replace) {
          container.empty();
          error.appendTo(container);
      }
      else {
          error.hide();
      }
      }
      

      最后,使用 HtmlExtensions.ValidationMessage 创建复选框组的错误范围。

      @Html.ValidationMessage("CheckBoxGroup", new { @class = "text-danger" }) 
      

      保留“input-validation-error”类是必要的,这样jquery验证器将验证复选框组的所有3个元素(电子邮件、电话、传真)作为一个整体,而不是一个一个地验证。不显眼的验证库默认在函数 onError 上删除这个类,所以我们必须自定义它,如上面的函数 onGroupError 所示。

      【讨论】:

        猜你喜欢
        • 2012-11-16
        • 1970-01-01
        • 1970-01-01
        • 2012-03-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-13
        相关资源
        最近更新 更多