客户端表单验证和交互的最佳 JavaScript 解决方案?

问题描述:

我们的网络表单非常复杂.什么是可扩展表单验证的好解决方案,最好是与 jQuery 一起使用的解决方案?

Our web forms are really complex. What's a great solution for extensible form validation, preferably one that works with jQuery?

背景:

我们的网站有一些 Ajax,但真正的重点是通过大约 20 个多页表单或向导"来实现用户体验.这些表格很复杂.

Our site has a bit of Ajax, but the real focus is on user experience through about 20 multi-page forms or "wizards." These forms are complicated.

  • 演示:有些字段是浮点数或整数.验证意味着去除非十进制字符,但我们还希望确保,如果用户在价格字段中输入 5,该字段将更新为 5.00.莉>
  • 副作用:某些字段在更新时会产生副作用.例如,更新商品的价格或数量需要更新小计字段.
  • 小部件驱动的元素:某些字段是隐藏的,并且具有由小部件填充的值.例如,地图小部件可让您指向某个位置,并且使用经纬度坐标更新隐藏字段,但该位置必须在某个区域内.
  • :有些字段是组,例如地址/城市/州/邮编,只有在填充所有字段后才应进行验证.
  • 服务器端验证:某些字段的验证需要通过 Ajax 请求进行后端检查
  • 每页多个表单:有时用户需要先填写一个表单,然后才能打开另一个表单的对话框.框架必须比绑定到 onSubmit 更通用——我们有时使用 Ajax 从同一页面按顺序发布多个表单.(例如,我们让用户一次性注册并创建一个小部件,但由于遗留系统,该流程需要两个 POST 请求.)
  • 可自定义的错误显示:有时错误出现在字段上方,有时字段样式会发生变化,我们的新设计需要类似工具提示的弹出窗口(ala qTip) 一些错误.
  • 活泼:用户体验是关键,触觉反馈也很重要.任何解决方案
  • 提交按钮:点击提交按钮需要验证所有内容,然后显示响应——但由于某些验证是异步发生的.
  • Presentation: Some fields are floats or ints. Validation means stripping non-decimal characters, but we also want to make sure that, if a user enters 5 into a price field, the field is updated to 5.00.
  • Side effects: Some fields have side effects when updated. E.g., updating the price or quantity of an item needs to update a subtotal field.
  • Widget-driven elements: Some fields are hidden and have values populated by widgets. E.g., a map widget lets you point to a location and a hidden field is updated with latitude-longitude coordinates, but the location must be within a certain region.
  • Groups: Some fields are groups, like address/city/state/zip, and should only be validated when all of the fields have bee populated.
  • Server-side validation: Validation of some fields requires back-end checking via Ajax requests
  • Multiple forms per page: Sometimes a user needs to fill out one form before a dialog opens with another form. A framework has to be more versatile than binding to onSubmit — we sometimes post multiple forms in order from the same page using Ajax. (E.g., we let users sign up and create a widget in one swoop but, due to legacy systems, that flow requires two POST requests.)
  • Customizable error display: Sometimes errors appear above fields, sometimes the field style changes, and our new designs call for tooltip-like popups (ala qTip) for some errors.
  • Snappiness: User experience is key and tactile feedback is important. Any solution
  • Submit buttons: Clicking the submit button needs to validate everything and then show a response — but since some of the validation happens asynchronously.

我们目前正在使用 jQuery 验证 库,但我们的表单似乎超出了它的能力.我一直在研究诸如 <angular/>KnockoutBackbone.js,但我担心他们太重量级或者他们会要求我们重写我们的前端.

We're currently using the jQuery Validation library but our forms appear to be outgrowing its capability. I've been looking at things like <angular/>, Knockout and Backbone.js, but I'm worried that they're too heavyweight or that they would require us to rewrite our frontend.

(这应该是一个社区维基.)

(This should be a community wiki.)

这是一个无耻的插件,但我可以自愿提供一个 框架 是我设计的吗?我已经基于注释(a la Hibernate Validator)构建了它.它支持自定义约束,我觉得它非常强大.Here 也是一个 * 问题,我要求对框架.

This is a shameless plug, but might I volunteer a framework that I designed? I've built it based on annotations (a la Hibernate Validator). It has support for custom constraints and I feel that it is pretty powerful. Here is also a * question where I asked for a review of the framework.

  • 演示:使用自定义验证约束,您可以将验证绑定到 onChange 元素.此外,由于 Regula 支持自定义验证器,您可以让自定义验证器更新字段的值(因此将 5 更改为 5.00).
  • 副作用:Regula 通过自定义约束验证器支持副作用.
  • :Regula 支持验证组.您可以针对特定组进行验证.通过组合自定义验证器和组,您可以控制验证器的行为,以便在填充该组的所有元素时验证(尽管您必须通过普通的 Javascript 执行此检查).
  • 服务器端验证:通过自定义约束,您可以进行 AJAX 调用来执行服务器端验证.根据当前框架的结构方式,这必然是一个阻塞的 ajax 调用.我计划在未来添加异步功能.
  • 每页有多个表单:Regula 不限于每页验证一个表单.它可以处理多种形式(不确定我是否正确理解您的要求 - 所以我可能没有正确回答这部分).
  • 可自定义的错误显示:就验证而言,Regula 不会对页面的 UI 执行任何操作.验证时,您会得到一组包含错误消息等的约束违规.如何显示它们取决于您.
  • Snappiness:我没有执行任何基准测试,所以我无法评论我的框架在这​​方面的表现.
  • 提交按钮:这是我尚未解决的问题(异步与同步).
  • Presentation: With custom validation-constraints, you can bind validation to the onChange element. Also, because Regula supports custom validators, you can have your custom validator update the value of a field (so change 5 to 5.00).
  • Side effects: Regula supports side-effects via custom constraint-validators.
  • Groups: Regula supports validation groups. You can target specific groups for validation. By combining a custom validator and a group, you can control the behavior of the validator so that it validates only when all elements of that group are filled (you would have to perform this check via normal Javascript though).
  • Server-side validation: With custom-constraints, you can make an AJAX call to perform server-side validation. With the way the framework is structured currently, this necessarily has to be a blocking ajax-call. I plan on adding an asynchronous feature in the future.
  • Multiplee forms per page: Regula isn't limited to validating one form per page. It can handle multiple forms (not sure if I understood your requirement correctly - so I might not have answered this part correctly).
  • Customizable error display: Regula doesn't do anything to the UI of the page as far as validation is concerned. When you validate, you get a set of constraint violations that contain error messages and such. It is up to you, how to display them.
  • Snappiness: I haven't performed any benchmarks, so I cannot comment as to my framework's performance in this regard.
  • Submit buttons: This is something I have yet to solve (asynchronous vs. synchronous).

这里有几个例子:

以下显示了带有内置约束的标准验证:

The following shows standard validation, with built-in constraints:

<input id = "myInput"
       name = "myInput"
       type = "text"
       class = "regula-validation"
       data-constraints = '@NotEmpty @IsNumeric @Between(min=1, max=5)' />

jQuery(document).ready(function() {
    // must call regula.binnd() first. The best place would be in an
    // onload handler. This function looks for elements with
    // a class name of "regula-validation" and binds the
    // appropriate constraints to the elements

    regula.bind(); 

    jQuery("#myForm").submit(function() {
        // this function performs the actual validation
        var validationResults = regula.validate();

        for(var index in validationResults) {
             var validationResult = validationResults[index];
             alert(validationResult.message);
        }
    });
});

如您所见,您只处理违反约束的情况,因此显示错误消息的方式完全取决于您.

As you can see, you're only working with constraint violations, and so the manner in which you display the error message is entirely up to you.

以下是自定义约束的示例:

Here's an example of a custom constraint:

regula.custom({
   name: "MustBe42",
   defaultMessage: "The answer must be equal to 42",
   validator: function() {
      return this.value == 42;
   }
});

及其用途:

<input id = "theAnswerToLifeTheUniverseAndEverything" 
       name = "theAnswerToLifeTheUniverseAndEverything" 
       value = ""
       class = "regula-validation"
       data-constraints = "@MustBe42" />

因为验证器是一个 Javascript 函数,你可以让它做任何事情(所以这解决了你关于副作用的问题).

Since the validator is a Javascript function, you can have it do anything (so this addresses your question about side effects).

这是另一个接受参数的约束示例:

Here is an example of another constraint that accepts parameters:

regula.custom({
   name: "DivisibleBy",
   defaultMessage: "{label} must be divisible by {divisor}",
   params: ["divisor"],
   validator: function(params) {
      var divisor = params["divisor"];
      return (this.value % divisor) == 0;
   }
});

和用法:

<input id = "number" 
       name = "number" 
       value = ""
       class = "regula-validation"
       data-constraints = "@DivisibleBy(divisor=3, label='The Number')" />

以下是使用验证组的示例:

Here is an example of using validation groups:

<input id = "score"
       name = "score"
       type = "text"
       class = "regula-validation"
       data-constraints = '@IsNumeric(label="Score", 
                                      message="{label} needs to be a number!"
                                      groups=[FirstGroup, SecondGroup, ThirdGroup]' />

<input id = "age"
       name = "age"
       type = "text"
       class = "regula-validation"
       data-constraints = '@IsNumeric(label="Age", 
                                      message="{label} needs to be a number!"
                                      groups=[SecondGroup]' />

<input id = "name"
       name = "name"
       type = "text"
       class = "regula-validation"
       data-constraints = '@NotEmpty(label="Name", 
                                     message="{label} cannot be empty!"
                                     groups=[FirstGroup]' />

还有一个只验证 FirstGroup 的片段(所以只有 scorename 被验证):

And a snippet that validates only FirstGroup (so only score and name are validated):

var constraintViolations = regula.validate({groups: [regula.Group.FirstGroup]});
var messages = "";

for(var index in constraintViolations) {
      var constraintViolation = constraintViolations[index];
      messages += constraintViolation.message + "
";
}

if(messages != "") {
   alert(messages);
}

如果您打算尝试一下,我建议您下载 1.1.1 版本.当前文档特别匹配该版本.在 1.2.1 中,我添加了对复合约束的支持,但我没有更新我的文档来反映这一点.

If you're planning on trying it out, I recommend downloading version 1.1.1. The current documentation matches that version specifically. In 1.2.1 I added support for compound constraints, but I haven't updated my documentation to reflect that.

我理解这是否不能解决您的所有问题,或者这不是您想要的.我以为我只是把它放在那里.此外,如果您确实检查了它,那么我将确保更新文档以反映版本 1.2.1.我一直忙于学校和工作,所以我没有时间去做.

I understand if this doesn't address all your concerns, or if this is not what you are looking for. I thought I'd just put it out there. Also, if you do check it out then I will make sure to update the documentation to reflect version 1.2.1. I've been busy with school and work and so I haven't had the time to do that.

更新 #1

Sohnee 提到了客户端验证.我实际上正在研究 Regula 和 Spring 3 之间的集成.希望我能很快发布它(再次取决于工作和学校).集成的工作原理是将 Hibernate 验证约束转换为 Regula 验证约束.这样,您只需编写一次验证代码(大多数情况下).但是对于自定义约束,您仍然需要在 Javascript 端(自定义验证器)编写代码.但是一旦您使用 Hibernate 验证约束在服务器端注释代码,您就无需在客户端执行任何操作;这些约束会自动应用于客户端的表单元素.

Sohnee mentioned client-side validation. I'm actually working on an integration between Regula and Spring 3. Hopefully I should be able to release it sometime soon (depending again, on work and school). The integration works by translating Hibernate validation-constraints to Regula validation-constraints. This way, you only have to write validation code once (mostly). For custom constraints though, you will still have to write code on the Javascript side (the custom validator). But once you annotate code on the server-side with Hibernate validation-constraints, you don't need to do anything on the client-side; those constraints automatically get applied to form elements on the client-side.

Matthew Abbott 也能够将 Regula 与 ASP.NET MVC 集成.

更新 #2

我有一个演示 web 应用程序(mavenized)on github 展示了Regula 和 Spring 3.0.x Web MVC 使用 Hibernate Validator.它没有真正记录或任何东西,它更像是概念证明.我计划向 github 页面添加一些关于集成及其工作原理的文档.

I've got a demo webapp (mavenized) on github that showcases the integration between Regula and Spring 3.0.x Web MVC using Hibernate Validator. It's not really documented or anything, it's more proof-of-concept. I plan to add some documentation to the github page about the integration and how it works.

更新 #3

我已经更新了 wiki 上的文档,现在它对应于最新的版本,1.2.2(我做了一个小错误修正,这就是为什么它现在是 1.2.2).

I've updated the documentation on the wiki, and it now corresponds to the latest version, 1.2.2 (I made a little bugfix, which is why it is 1.2.2 now).