Подтвердить что ты не робот

Рамка для проверки формы Javascript: запрос на обзор

Я не был уверен, могу ли я задать такой вопрос, но, увидев этот в Meta Stackoverflow, похоже, что этот вопрос в порядке. Что ж, на мой вопрос:

Несколько месяцев назад я написал структуру проверки в Javascript. Я знаю, что уже существуют рамки проверки, такие как jQuery Validation, но я хотел бы использовать другой подход к проверке. Современные подходы касаются написания кода Javascript для выполнения проверки элементов формы. Рассматривая исходный код формы, не сразу видно, какая проверка выполняется для каждого элемента. В какой-то мере это можно исправить, используя классы CSS, которые определяют разные виды проверки. Но я чувствовал, что даже это было ограничено, потому что вы не можете легко настроить поведение validaton (сообщения об ошибках и т.д.). Я хотел сделать что-то вроде проверки на основе аннотаций в Java, используя JSR-303 Bean Validation или Hibernate Validator.

Так как 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 и сервлеты) и переместили ее в Spring MVC. Когда разговор о проверке подошел, я разбил рамки для своего старшего архитектора. Я сделал небольшую интеграцию и доказал концепцию, и они, казалось, заинтересовались и дали мне возможность добавить ее в проект. До сих пор у меня было только собственное скромное мнение, что это будет полезный способ сделать валидацию, поэтому это дало мне некоторую уверенность в том, что моя идея и структура могут иметь некоторые достоинства. Тем не менее, мне все еще нужно было больше участия и рамки. После того, как я понял, что Stackoverflow разрешает подобные вопросы, я решил опубликовать его здесь, чтобы получить конструктивную критику, комментарии и отзывы.

Поэтому без каких-либо задержек я хотел бы ввести Regula. Ссылка, которую я предоставил, относится к вики на GitHub, которая имеет всю документацию для фреймворка. Вы можете загрузить последнюю версию (v1.1.0) из здесь.

Ждем ваших комментариев.

Дополнительная информация, которая не имеет непосредственного значения

Я поиграл с идеей интегрировать свою фреймворк с помощью Spring, т.е. перевести аннотации проверки на beans на проверку на стороне клиента. Недавно мне удалось заставить это работать, даже с группами проверки (хотя в настоящее время нет поддержки отношений наследования между группами на стороне клиента). Таким образом, вы просто должны аннотировать свойства поля с ограничениями проверки, и код проверки на стороне клиента автоматически генерируется. Тем не менее, я новичок Spring, поэтому мой метод, вероятно, не так уж и чист. Я хотел бы получить некоторые отзывы об этом, так что, если кто-то заинтересован, пожалуйста, дайте мне знать. В идеале (и я надеюсь, что я не слишком претенциозен), я хотел бы связаться с людьми Spring и посмотреть, заинтересованы ли они в этом.

4b9b3361

Ответ 1

Мне это очень нравится, он сохраняет мой 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);
}

Infact, я просто blogged об этом, так как я впечатлен тем, насколько он чист и легок. Я все еще собираюсь провести время, проходя через ваш источник, чтобы узнать, как вы его достигли, но это отличный старт:)

Что касается интеграции вашей инфраструктуры, я работаю в основном с ASP.NET MVC, и было бы интересно посмотреть, как она переводит логику проверки на стороне сервера в ограничения на стороне клиента. Что-то, что я мог бы рассмотреть в следующем месяце или около того.

Ответ 2

Я использую совершенно другой подход: в современных структурах, таких как 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