Javascript表单验证框架:请求审核

时间:2010-08-13 00:10:46

标签: javascript validation client-side-validation

我不确定我是否可以提出这样的问题,但在Meta Stackoverflow上看到this后,看起来这样的问题还可以。好吧,在我的问题上:

几个月前,我在Javascript中编写了一个验证框架。我知道已存在像jQuery Validation这样的验证框架,但我想采用不同的验证方法。当前的方法涉及编写Javascript代码以对表单元素执行验证。通过查看表单源代码,不会立即明确在每个元素上进行验证。在某种程度上,这可以通过使用指定不同类型的验证的CSS类来解决。但我觉得即使这样也是有限的,因为你无法轻松定制验证的行为(错误消息等)。我希望使用JSR-303 Bean ValidationHibernate Validator在Java中执行基于注释的验证。

由于HTML5允许您向元素添加自定义属性,我认为我可以利用它来“注释”表单元素以进行验证。所以,基本上,我想出了这个:

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

考虑到这个基本想法,我创建了一个Javascript框架:

  • 检查DOM中已定义约束的元素,并将这些约束绑定到元素
  • 允许创建自定义约束
  • 允许以编程方式绑定约束
  • 验证绑定约束

此外,该框架具有以下功能:

  • 验证组,类似于JSR-303
  • 中指定的验证组
  • 错误消息的插值

一旦我创建了我的框架,我就会尝试获得反馈并对其进行审核,但我不知道该去哪里获得反馈和审核。我写了一些关于它的博客文章并将其发布到Digg和Reddit(编程部分),没有太多运气。有些人似乎很感兴趣,但我没有得到更多。

最近,在我的工作场所,我们一直在对遗留代码库(JSP和servlet)进行现代化,并将其转移到Spring MVC中。当验证对话出现时,我将我的框架投给了我的高级架构师。我做了一点整合和概念验证,他们似乎很感兴趣,并让我继续将它添加到项目中。直到现在,我只有自己的拙见,这将是一种有用的验证方式,所以这让我有信心我的想法和框架可能有一些优点。但是,我仍然需要更多的参与和框架。在我发现Stackoverflow确实允许这些问题之后,我决定将它发布在这里以获得一些建设性的批评,评论和反馈。

所以我没有任何延迟,我想介绍Regula。我提供的链接转到GitHub上的wiki,其中包含该框架的所有文档。您可以从here下载最新版本(v1.1.0)。

期待您的意见。

一些不直接相关的额外信息

我曾经想过将我的框架与Spring集成,即将bean上的验证注释转换为客户端验证。最近我能够使这个工作,即使有验证组(虽然目前没有支持客户端组之间的继承关系)。这样,您只需使用验证约束来注释字段属性,并自动生成客户端验证代码。但是,我是一个春天的新手,所以我的方法可能不那么干净。我想得到一些反馈,所以如果有人有兴趣请告诉我。理想情况下(我希望我不会太自命)我想联系春天的人,看看他们是否对此感兴趣。

2 个答案:

答案 0 :(得分:7)

我已经非常喜欢它了,它使我的html保持干净,并且构建自定义验证器的能力非常好。我添加的一件事是绑定验证和提交函数的简写,并将其包装为jQuery插件:

if (jQuery) {
    (function($)
    {
        $.regula = function(formId, callback) 
        {
            regula.bind();

            $("#" + formId).submit(function() 
            {
                var validationResults = regula.validate();

                if (validationResults.length > 0)
                {
                    if (callback)
                        callback(validationResults);

                    return false;
                }

                return true;
            });
        };
    })(jQuery);
}

事实上,我只是blogged关于它,因为我对它的干净和轻松印象深刻。我仍然会花时间浏览你的来源,看看你是如何完成它的,但它是一个很好的开始:)

关于集成框架,我主要使用ASP.NET MVC,看看它如何将服务器端验证逻辑转换为客户端约束将会很有趣。我可能会在接下来的一个月左右看一下。

答案 1 :(得分:0)

我正在使用完全不同的方法: 使用像React或Angular这样的现代框架,您始终会在javascript中的某个位置保持表单状态,而不是DOM输入状态(DOM只是数据的视图层)。而且我认为应该是这样的,因为无论您使用哪种华丽的组件来构建表单,都始终在对象下面包含所有状态。从这点到我,自然的方法是只使用原始JSR-303(不带注释)来验证该对象(因为JSR-303为您提供了这种灵活性)并将错误填充回DOM。让我给你看一个例子:

import React, { Component } from "react";
import ReactDOM from "react-dom";

import validator, {
  Collection,
  All,
  Required,
  Optional,
  NotBlank,
  Length,
  Email
} from "@stopsopa/validator";

class App extends Component {
  constructor(...args) {
    super(...args);
    this.state = {
      data: {
        name: "",
        email: "",
        comments: []
      },
      errors: {},
      validate: false
    };
  }
  onSubmit = async e => {
    e.preventDefault();

    const errors = await validator(
      this.state.data,
      new Collection({
        name: new Required([new NotBlank(), new Length({ min: 3 })]),
        email: new Required([new NotBlank(), new Email()]),
        comments: new All([new NotBlank(), new Length({ min: 10 })])
      })
    );
    this.setState({
      errors: errors.getTree(),
      validate: true
    });

    if (!errors.count()) {
      console.log("send data to server", this.state.data);
    }
  };
  onChange = (name, value) => {
    console.log(name, value);
    this.setState(state => ({
      ...state,
      data: { ...state.data, ...{ [name]: value } }
    }));
  };
  addComment = () =>
    this.setState(state => {
      const comments = state.data.comments;
      comments.push("");
      const newState = { ...state };
      newState.data.comments = comments;
      return newState;
    });
  deleteComment = i =>
    this.setState(state => {
      const newState = { ...state };
      state.data.comments.splice(i, 1);
      return newState;
    });
  editComment = (i, value) => {
    this.setState(state => {
      const newState = { ...state };
      state.data.comments[i] = value;
      return newState;
    });
  };
  render() {
    const s = this.state;
    console.log("state", JSON.stringify(s, null, 4));
    return (
      <form onSubmit={this.onSubmit}>
        <label>
          name:
          <input
            value={s.data.name}
            onChange={e => this.onChange("name", e.target.value)}
          />
        </label>
        {s.validate && s.errors.name && (
          <div className="error">{s.errors.name}</div>
        )}
        <br />
        <label>
          email:
          <input
            value={s.data.email}
            onChange={e => this.onChange("email", e.target.value)}
          />
        </label>
        {s.validate && s.errors.email && (
          <div className="error">{s.errors.email}</div>
        )}
        <div>
          comments:{" "}
          <a onClick={this.addComment} href="javascript:void(0)">
            add
          </a>
          {s.data.comments.map((m, i) => (
            <div style={{ border: "1px solid red" }} key={i}>
              <textarea
                rows="2"
                value={m}
                onChange={e => this.editComment(i, e.target.value)}
              />
              <a
                onClick={() => this.deleteComment(i)}
                href="javascript:void(0)"
              >
                delete
              </a>
              {s.validate && s.errors.comments && s.errors.comments[i] && (
                <div className="error">{s.errors.comments[i]}</div>
              )}
            </div>
          ))}
        </div>
        <br />
        <input type="submit" value="submit" />
      </form>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

生活示例https://codesandbox.io/s/ymwky9603j