14

この種の質問をすることができるかどうかはわかりませんでしたが、Meta Stackoverflowでこれを見た後、この種の質問は問題ないようです。さて、私の質問に:

数ヶ月前、私はJavascriptで検証フレームワークを作成しました。jQuery Validationのような検証フレームワークがすでに存在することは知っていますが、検証には別のアプローチを取りたかったのです。現在のアプローチは、フォーム要素の検証を実行するためのJavascriptコードの記述を扱っています。フォームのソースコードを見ると、各要素でどのような検証が行われているかがすぐにはわかりません。これは、さまざまな種類の検証を指定するCSSクラスを使用することである程度改善できます。しかし、検証の動作(エラーメッセージなど)を簡単にカスタマイズできないため、これでも制限があると感じました。JSR-303 BeanValidationまたはHibernateValidatorを使用して、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とサーブレット)を最新化して、SpringMVCに移行しています。検証の会話が出てきたとき、私は自分のフレームワークを上級アーキテクトに売り込みました。私は少し統合して概念実証を行いましたが、彼らは興味を持っているようで、プロジェクトに追加するためのゴーサインをくれました。今まで、これは検証を行うのに役立つ方法だと私自身の謙虚な意見しか持っていなかったので、これは私のアイデアとフレームワークに何らかのメリットがあるかもしれないという自信を与えてくれました。しかし、私はまだもう少し参加とフレームワークが必要でした。Stackoverflowでこの種の質問が可能であることがわかった後、建設的な批判、コメント、フィードバックを得るために、ここに投稿することにしました。

それで、これ以上遅れることなく、レギュラを紹介したいと思います。私が提供したリンクは、フレームワークのすべてのドキュメントが掲載されているGitHubのwikiに移動します。ここから最新バージョン(v1.1.0)をダウンロードできます。

コメントをお待ちしております。

すぐには関係のないいくつかの追加情報

フレームワークをSpringと統合する、つまりBeanの検証アノテーションをクライアント側の検証に変換するというアイデアをいじくりまわしていました。最近、検証グループを使用しても、これを機能させることができました(ただし、現在、クライアント側のグループ間の継承関係はサポートされていません)。このように、検証制約でフィールドプロパティに注釈を付けるだけで、クライアント側の検証コードが自動的に生成されます。しかし、私は春の初心者なので、私の方法はおそらくそれほどきれいではありません。これについてもフィードバックをいただきたいので、興味のある方はお知らせください。理想的には(そして私があまり気取らないことを願っています)私は春の人々に連絡して、彼らがこれに興味があるかどうかを確認したいと思います。

4

2 に答える 2

7

私はすでにそれがとても好きです、それは私のhtmlをきれいに保ち、カスタムバリデーターを構築する能力は素晴らしいです。私が追加したものの1つは、検証関数と送信関数をバインドするための省略形であり、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);
}

実際、私はそれがいかにクリーンで簡単であるかに感銘を受けたので、それについてブログを書きました。私はまだあなたの情報源を調べて、あなたがそれをどのように達成したかを見るために時間を費やすつもりですが、それは素晴らしいスタートです:)

フレームワークの統合に関しては、主にASP.NET MVCを使用していますが、サーバー側の検証ロジックがクライアント側の制約にどのように変換されるかを確認するのは興味深いことです。来月かそこらで見渡すかもしれない何か。

于 2010-08-13T22:08:30.183 に答える
0

私はまったく異なるアプローチを取っています。ReactやAngularのような最新のフレームワークでは、常にDOM入力状態ではなくjavascriptのどこかにフォームの状態があります(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

于 2018-12-05T16:59:02.290 に答える