Валидация на стороне клиента

Mithril — это лёгкий и быстрый JavaScript-фреймворк для создания одностраничных приложений. Одним из ключевых аспектов современных веб-приложений является валидация данных на стороне клиента, которая позволяет проверять корректность ввода до отправки на сервер. В контексте Mithril этот процесс тесно связан с реактивностью компонентов и управлением состоянием формы.


Модели и состояние формы

В Mithril отсутствует встроенная система моделей, поэтому данные формы обычно хранятся в простых объектах Jav * aScript:

const formData = {
    username: "",
    email: "",
    password: ""
};

const errors = {};

Здесь formData хранит значения полей формы, а объект errors — сообщения об ошибках. Такой подход упрощает динамическое управление состоянием и проверку данных.


Функции валидации

Валидация реализуется через отдельные функции, которые проверяют каждое поле:

function validateUsername(username) {
    if (!username) return "Имя пользователя не может быть пустым";
    if (username.length < 3) return "Имя пользователя должно содержать минимум 3 символа";
    return null;
}

function validateEmail(email) {
    const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!email) return "Email обязателен";
    if (!emailPattern.test(email)) return "Неверный формат email";
    return null;
}

function validatePassword(password) {
    if (!password) return "Пароль обязателен";
    if (password.length < 6) return "Пароль должен содержать минимум 6 символов";
    return null;
}

Каждая функция возвращает либо строку с ошибкой, либо null, если поле корректно. Такой подход облегчает проверку формы перед отправкой данных.


Обработка событий ввода

Mithril использует виртуальный DOM, поэтому события ввода обрабатываются через атрибуты компонентов:

m("input[type=text]", {
    value: formData.username,
    oninput: (e) => {
        formData.username = e.target.value;
        errors.username = validateUsername(formData.username);
    }
})

Аналогично обрабатываются остальные поля. При каждом изменении значения запускается соответствующая функция валидации и обновляется объект errors. Это обеспечивает немедленную обратную связь пользователю.


Визуализация ошибок

Ошибки можно отобразить рядом с полем ввода с помощью условного рендера:

m("div.form-group", [
    m("label", "Имя пользователя"),
    m("input[type=text]", {
        value: formData.username,
        oninput: (e) => {
            formData.username = e.target.value;
            errors.username = validateUsername(formData.username);
        }
    }),
    errors.username ? m("div.error", errors.username) : null
])

Такой подход делает интерфейс интерактивным и понятным: пользователи видят ошибки сразу, а не после отправки формы.


Валидация при отправке формы

Для окончательной проверки перед отправкой данных создаётся агрегирующая функция:

function validateForm() {
    errors.username = validateUsername(formData.username);
    errors.email = validateEmail(formData.email);
    errors.password = validatePassword(formData.password);

    return !errors.username && !errors.email && !errors.password;
}

При отправке формы можно использовать её результат:

function submitForm() {
    if (validateForm()) {
        console.log("Форма корректна", formData);
        // вызов API или другая логика
    } else {
        console.log("Есть ошибки", errors);
    }
}

Реактивность и перерисовка

В Mithril важно вручную вызывать m.redraw() в случаях, когда изменения состояния происходят вне встроенных обработчиков событий. Например, при асинхронной валидации или получении ошибок от сервера:

async function asyncValidateEmail(email) {
    const response = await fetch(`/validate-email?email=${email}`);
    const result = await response.json();
    errors.email = result.valid ? null : "Email уже используется";
    m.redraw();
}

Композиция валидаторов

Для крупных форм удобно комбинировать валидаторы. Можно создать объект с правилами:

const validators = {
    username: validateUsername,
    email: validateEmail,
    password: validatePassword
};

function validateAll(data) {
    const errors = {};
    for (const field in validators) {
        errors[field] = validators[field](data[field]);
    }
    return errors;
}

Это позволяет динамически проверять поля, добавлять новые правила и уменьшает дублирование кода.


Асинхронная и условная валидация

Некоторые поля требуют проверки на сервере, например, уникальность имени пользователя. В таких случаях валидация делится на синхронную и асинхронную:

function validateUsernameAsync(username) {
    if (!username) return Promise.resolve("Имя пользователя не может быть пустым");
    return fetch(`/check-username?username=${username}`)
        .then(res => res.json())
        .then(data => data.available ? null : "Имя уже занято");
}

Асинхронные валидаторы интегрируются с синхронной проверкой через промисы, что позволяет отображать ошибки по мере их поступления.


Вывод

Валидация на стороне клиента в Mithril строится на управлении состоянием формы, функциях проверки данных и условном рендеринге ошибок. Использование реактивного подхода и разделение синхронной и асинхронной валидации позволяет создавать интерактивные, быстрые и удобные формы, минимизируя количество некорректных запросов к серверу.