用于客户端表单validation和交互的最佳JavaScript解决scheme?

我们的网页forms非常复杂。 什么是可扩展的表单validation的一个很好的解决scheme,最好是与jQuery一起工作?

背景:

我们的网站有一点Ajax,但真正的重点是通过大约20个多页面表单或“向导”的用户体验。 这些forms很复杂。

  • 介绍:一些领域是浮动或整数。 validation意味着剥离非十进制字符,但我们也要确保,如果用户在价格字段中input5 ,字段更新为5.00
  • 副作用:更新时,某些字段有副作用。 例如,更新物品的价格或数量需要更新小计字段。
  • 小部件驱动的元素:有些字段是隐藏的,并有小部件填充的值。 例如,一个地图小部件可以让你指向一个位置,一个隐藏的字段用经度 – 纬度坐标来更新,但是该位置必须在一定的区域内。
  • 组:一些字段是组,如地址/城市/国家/邮政编码,只应该validation所有的领域都蜂填充。
  • 服务器端validation:validation某些字段需要通过Ajax请求进行后端检查
  • 每页多个表单:有时用户需要填写一个表单,然后用另一个表单打开一个对话框。 框架必须比绑定onSubmit更通用 – 我们有时会使用Ajax从同一页面按顺序发布多个表单。 (例如,我们让用户注册并创build一个小部件,但由于遗留系统,该stream程需要两个POST请求。)
  • 可定制的错误显示:有时错误出现在字段上方,有时字段样式会发生变化,而且我们的新devise会针对某些错误调用类似于工具提示的popup窗口(ala qTip )。
  • 快乐:用户体验是关键,触觉反馈非常重要。 任何解决scheme
  • 提交button:点击提交button需要validation一切,然后显示响应 – 但由于一些validation发生asynchronous。

我们目前正在使用jQueryvalidation库,但是我们的表单似乎超出了它的function。 我一直在寻找像<angular /> , Knockout和Backbone.js这样的东西 ,但是我担心它们太重了,或者他们会要求我们重写我们的前端。

(这应该是一个社区wiki。)

这是一个无耻的插件,但我可以自愿devise一个框架吗? 我已经build立了基于注释(一个Hibernatevalidation器)。 它支持自定义约束,我觉得它非常强大。 这里也是一个Stackoverflow的问题,我问的框架的审查。

  • 演示 :使用自定义validation约束,可以将validation绑定到onChange元素。 此外,由于Regula支持自定义validation器,因此您可以让自定义validation器更新字段的值(将5更改为5.00 )。
  • 副作用 :Regula通过自定义约束validation器支持副作用。
  • :Regula支持validation组。 您可以定位特定组进行validation。 通过组合一个自定义的validation器和一个组,你可以控制validation器的行为,使得validation器只有当该组的所有元素都被填充时才能validation(你必须通过普通的Javascript执行这个检查)。
  • 服务器端validation :使用自定义约束,您可以进行AJAX调用来执行服务器端validation。 通过框架的构build方式,这必然是一个阻塞的Ajax调用。 我计划在将来添加一个asynchronousfunction。
  • 每个页面的多重表单 :Regula不限于每页validation一个表单。 它可以处理多种forms(不知道我是否正确理解您的要求 – 所以我可能没有正确回答这个部分)。
  • 可定制的错误显示:就validation而言,Regula对页面的UI没有任何作用。 validation时,会得到一组包含错误消息等的约束违规。 这取决于你,如何显示它们。
  • Snappiness:我没有执行任何基准,所以我不能评论我的框架在这​​方面的performance。
  • 提交button:这是我还没有解决(asynchronous与同步)。

这里有一些例子:

以下显示标准validation,内置约束条件:

 <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); } }); }); 

正如你所看到的,你只能处理约束违规,所以显示错误信息的方式完全取决于你。

以下是一个自定义约束的例子:

 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" /> 

由于validation器是一个JavaScript函数,你可以让它做任何事情(所以这解决了有关副作用的问题)。

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

 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')" /> 

以下是使用validation组的示例:

 <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]' /> 

并且只validationFirstGroup的片段(所以只有scorename被validation):

 var constraintViolations = regula.validate({groups: [regula.Group.FirstGroup]}); var messages = ""; for(var index in constraintViolations) { var constraintViolation = constraintViolations[index]; messages += constraintViolation.message + "\n"; } if(messages != "") { alert(messages); } 

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

我明白,如果这不能解决您的所有疑虑,或者如果这不是你正在寻找。 我以为我只是把它放在那里。 另外,如果您确实检查了一下,我将确保更新文档以反映版本1.2.1 。 我一直忙于学习和工作,所以我没有时间去做这件事。

更新#1

Sohnee提到了客户端validation。 实际上,我正在Regula和Spring 3之间进行整合。希望我能够在不久的将来发布它(取决于工作和学校)。 通过将Hibernatevalidation约束转换为Regulavalidation约束来实现集成。 这样,你只需要写一次validation码(主要是)。 尽pipe对于自定义约束,你仍然需要在Javascript端(自定义validation器)编写代码。 但是,一旦用Hibernatevalidation约束在服务器端注释代码,就不需要在客户端执行任何操作。 这些约束自动应用于客户端的表单元素。

Matthew Abbott也能够将Regula和ASP.NET MVC整合在一起 。

更新#2

我在github上有一个demo webapp(mavenized),展示了使用Hibernate Validator在Regula和Spring 3.0.x Web MVC之间的集成。 这不是真正的文件或任何东西,这是更多的概念validation。 我打算将一些文档添加到GitHub页面关于集成和如何工作。

更新#3

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

我已经使用这个jQuery formValidator几次与一大堆不同的环境。 我希望这会有所帮助,因为我很less花费一个多小时来设置它。

干杯!

我会说jQueryvalidation插件做得很好。 我把它和元数据插件结合起来,把服务器端的validationparameter passing给客户端。 我还包含了几个关键点,以便我可以使用通用模式进行validation,以及一些特殊/自定义状态。 这包括自定义警报消息和显示。

它没有做你想要的所有东西,但它是我见过的最好的select和最好的默认行为。 我再一次使用它的元数据(属性“数据元”)。 它可以弯曲你的意志。 我也使用元数据控制绑定到input元素客户端。 这将我的客户端逻辑从服务器端分离出来,但从长远来看,从服务器端逻辑中注入js更容易。

写作时Parsley.js看起来是一个不错的和stream行的select(2013年8月)。

自从我们团队中的某个人注意到了jQuery Tools的Validator后,自己回答这个问题!

  • 演示文稿 – 支持HTML5input字段。 pattern字段确保用户只能以某种模式inputtesting。
  • 副作用 – 触发窗体上和各个字段上的事件: onFailonSuccess
  • 小部件驱动的元素 – “自定义inputtypes”,鼓励。 基本演示甚至包括一个自然数字的“年龄”字段。
  • – 写一个“函数匹配器”,其唯一目的是过滤哪些字段将被validation。
  • 服务器端validation – 执行并智能地执行 – 取决于您的validation器调用callback(因此它是asynchronous友好的)而不是返回值。
  • 每页多个表单 – jQuery Tools似乎已经很好的build立了,这应该不成问题。
  • 可定制的错误显示 – 字段旁边的错误? 所有在一个地方? 没问题。 还不够好? 绑定事件失败。 甚至默认使用工具提示。
  • Snappiness – 演示非常活泼
  • 提交button – 没问题。

更新:是的 ,只是用jQuery Tools的validation工具提示重新实现了我们网站的一大块。 太棒了!

服务器端validation岩石。

如果您喜欢,请通过AJAX请求提供此类validation的结果…或者使用也将添加客户端validation的服务器端框架,但不要将其写入两次。

去与jQueryvalidation插件。 迄今为止,它从未失败过

  function isEmpty(text) { if(text == undefined) { return true; } if(text.replace(/\s+/g, ' ').length == 0) { return true; } return false; } function isValidBoolean(text) { if(text == undefined || (text.toLowerCase() != "true" && text.toLowerCase() != "false")) { return false; } return true; } function isValidDouble(text) { var out = parseFloat(text); if(isNaN(out)) { return false; } return true; } function isValidLong(text) { var out = parseInt(text); if(isNaN(out)) { return false; } return true; } function isValidDate(text) { if(Date.parseString(text, 'MM/dd/yyyy HH:mm:ss') == null) { return false; } return true; } function hasDuplicates(array) { var valuesSoFar = {}; for (var i = 0; i < array.length; ++i) { var value = array[i]; if (Object.prototype.hasOwnProperty.call(valuesSoFar, value)) { return true; } valuesSoFar[value] = true; } return false; }