Рамка для проверки формы 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 и посмотреть, заинтересованы ли они в этом.
Ответы
Ответ 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