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

时间:2011-01-20 19:44:02

标签: javascript jquery html validation forms

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

背景:

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

  • 演示文稿:某些字段是浮点数或整数。验证意味着剥离非小数字符,但我们还要确保,如果用户在价格字段中输入5,该字段将更新为5.00
  • 副作用:某些字段在更新时会产生副作用。例如,更新项目的价格或数量需要更新小计字段。
  • 窗口小部件驱动的元素:隐藏某些字段并使用窗口小部件填充值。例如,地图小部件可让您指向某个位置,隐藏的字段会使用纬度 - 经度坐标进行更新,但该位置必须位于特定区域内。
  • 群组:某些字段是群组,例如地址/城市/州/邮政编码,只应在填写完所有字段后进行验证。
  • 服务器端验证:某些字段的验证需要通过Ajax请求进行后端检查
  • 每页多个表单:有时用户需要在使用其他表单打开对话框之前填写一个表单。框架必须比绑定到onSubmit更通用 - 我们有时使用Ajax从同一页面按顺序发布多个表单。 (例如,我们让用户一次注册并创建一个小部件,但由于遗留系统,该流需要两个POST请求。)
  • 自定义错误显示:有时错误会显示在字段上方,有时字段样式会发生变化,而我们的新设计会针对某些错误调用类似工具提示的弹出窗口(ala qTip)。
  • Snappiness:用户体验是关键,触觉反馈非常重要。任何解决方案
  • 提交按钮:点击提交按钮需要验证所有内容,然后显示响应 - 但由于部分验证是异步发生的。

我们目前正在使用jQuery Validation库,但我们的表单似乎已超出其功能。我一直在关注<angular/>KnockoutBackbone.js等内容,但我担心他们太重量级或者他们会要求我们重写我们的前端。

(这应该是社区维基。)

8 个答案:

答案 0 :(得分:55)

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

  • 演示文稿:使用自定义验证约束,您可以将验证绑定到onChange元素。此外,由于Regula支持自定义验证程序,您可以让自定义验证程序更新字段的值(因此将5更改为5.00)。
  • 副作用:Regula通过自定义约束验证器支持副作用。
  • 群组:Regula支持验证组。您可以将特定组作为目标进行验证。通过组合自定义验证器和组,您可以控制验证器的行为,以便在填充该组的所有元素时验证 (您必须通过正常的Javascript执行此检查)
  • 服务器端验证:使用自定义约束,您可以进行AJAX调用以执行服务器端验证。通过框架当前的结构方式,这必然是阻止ajax调用。我打算将来添加一个异步功能。
  • 每页多页表单:规则不限于每页验证一个表单。它可以处理多种形式(不确定我是否正确理解您的要求 - 所以我可能没有正确回答这一部分)。
  • 可自定义的错误显示:就验证而言,Regula对页面的UI没有任何作用。验证时,会收到一组包含错误消息等的约束违规。这取决于你,如何展示它们。
  • Snappiness:我没有执行任何基准测试,所以我不能评论我的框架在这​​方面的表现。
  • 提交按钮:这是我尚未解决的问题(异步与同步)。

以下是一些例子:

以下显示标准验证,内置约束:

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

由于验证器是一个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')" />

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

<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):

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

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

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

更新#1

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

Matthew Abbott也可以integrate Regula with ASP.NET MVC

更新#2

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

更新#3

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

答案 1 :(得分:13)

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

干杯!

答案 2 :(得分:8)

我会说jQuery Validation插件做得很好。我将它与metadata插件结合使用,将服务器端验证参数传递给客户端。我还为所有表单包含了几个关键点,以便我可以使用通用模式进行验证,以及一些特殊/自定义状态。这包括自定义警报消息和显示。

它没有开箱即用,但它是我见过的最佳选择和最佳默认行为。我再次使用元数据(属性“data-meta”)。它可以根据你的意愿弯曲。我也使用元数据来控制绑定到客户端的输入元素。这将客户端逻辑从服务器端拆分,但从长远来看,尝试从服务器端逻辑注入js更容易。

答案 3 :(得分:5)

在撰写本文时(2013年8月),

Parsley.js看起来是一个不错的选择。

答案 4 :(得分:2)

我自己回答了这个问题,因为我们团队中有人注意到 Validator from jQuery Tools

  • 演示文稿 - 支持HTML5输入字段。 pattern字段确保用户只能以特定模式输入测试。
  • 副作用 - 触发表单和各个字段上的事件:onFailonSuccess
  • 窗口小部件驱动的元素 - 鼓励“自定义输入类型”。基本演示甚至包括一个自然数字的“年龄”字段。
  • 群组 - 撰写“功能匹配器”,其唯一目的是过滤要验证的字段。
  • 服务器端验证 - 它是否智能地执行 - 取决于您的验证器调用回调(因此它是异步友好的)而不是返回值。
  • 每页多个表单 - jQuery Tools似乎构建得很好,这应该不是问题。
  • 自定义错误显示 - 字段旁边的错误?一切都在一个地方?没问题。还不够好吗?在失败时绑定事件。甚至默认使用工具提示。
  • Snappiness - 演示非常活泼
  • 提交按钮 - 没问题。

更新:是的,只需使用jQuery Tools的验证工具提示重新实现我们网站的一大块。奇妙!

答案 5 :(得分:1)

服务器端验证。

如果您愿意,可以通过AJAX请求提供此类验证的结果......或者使用也会添加客户端验证的服务器端框架,但不要写两次。

答案 6 :(得分:0)

使用jQuery Validation插件。到目前为止,它从未让我失望

答案 7 :(得分:0)

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