Как происходит валидация формы на js (JavaScript)

Валидация формы на js (JavaScript)

21.01.2024
229
22 мин.
0

Работа с формами — ежедневная задача практически для каждого веб-разработчика. Валидация формы на js (JavaScript) на стороне клиента — удобная функция.

Несмотря на то, что такая проверка формы на JavaScript обеспечивает удобство для пользователей, её можно очень легко обмануть и обойти. Чтобы снизить риски её вредоносного использования, лучше проверять введённую информацию на стороне сервера.

Что такое проверка формы

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

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

Варианты проверки на стороне клиента

В этом случае доступны два варианта:

  1. Разработка логики валидации формы на чистом js или с использованием библиотеки.
  2. Встроенная проверка формы на HTML (этот вариант является лучшим по сравнению с первым, но уступает ему в гибкости).

Валидация формы на js: постановка задачи

Для начала создадим простую форму регистрации с четырьмя полями:

  • имя пользователя;
  • адрес электронной почты;
  • пароль;
  • подтверждение пароля.

При нажатии кнопки отправки формы без заполнения или внесения данных неправильного формата, будут отображаться сообщения об ошибках.

Рассмотрим пример валидации формы js, который включает следующие пункты:

  • поле для имени пользователя не может быть пустым и должно содержать от 3 до 25 символов;
  • электронная почта обязательна и должна быть соответствующего формата;
  • пароль должен состоять минимум из восьми символов (в него необходимо включить минимум один символ нижнего и один символ верхнего регистра, одну цифру и хотя бы один специальный символ из этого набора: !@#$%^&*);
  • данные в поле подтверждения пароля должны совпадать с полем для пароля.

Создание HTML-формы

<div class="container">
    <form id="signup" class="form">
        <h1>Регистрация</h1>
            <div class="form-field">
                <label for="username">Имя:</label>
                <input type="text" name="username" 
                 id="username" autocomplete="off">
                <small></small>
            </div>
            <div class="form-field">
                <label for="email">Email:</label>
                <input type="text" name="email" id="email" autocomplete="off">
                <small></small>
            </div>
            <div class="form-field">
                <label for="password">Пароль:</label>
                <input type="password" name="password" id="password" autocomplete="off">
                <small></small>
            </div>
            <div class="form-field">
                <label for="confirm-password">Подтвердите пароль:</label>
                <input type="password" name="confirm-password" id="confirm-password" autocomplete="off">
                <small></small>
            </div>
           <div class="form-field">
                <input type="submit" value="Зарегистрироваться">
            </div>
    </form>
</div>

Примечательной особенностью этой формы регистрации является то, что каждое поле заключено в div с классом form-field и включает три элемента:

  • label;
  • input;
  • элемент <small>.

Последний будет использоваться для показа пользователю сообщения об ошибке. Если в input введены недопустимые данные, его border будет становиться красного цвета путём добавления класса error к элементу form-field. Это будет выглядеть следующим образом:

<div class="form-field error">
   <label for="username">Имя пользователя:</label>
   <input type="text" name="username" id="username" autocomplete="off">
   <small></small>
</div>

Если в input введены правильные данные, то цвет его border, будет меняться на зелёный, через добавление класса success к элементу form-field:

<div class="form-field success">
   <label for="username">Имя пользователя:</label>
   <input type="text" name="username" id="username" autocomplete="off">
   <small></small>
</div>

Добавляем простую стилизацию:

form {
  max-width: 400px;
  margin: 20px auto;
}

label {
  display: block;
  margin-bottom: 8px;
}

input {
  width: calc(100% - 20px);
  padding: 8px;
  margin-bottom: 16px;
}

input[type="submit"] {
  width: 100%;
}

input:focus {
  outline: none;
}

.error {
  color: red;
  margin-top: 5px;
}

.success {
  color: green;
}

Прослушиватель события отправки формы

Как происходит валидация формы на js (JavaScript)
Реализация проверки формы на JavaScript (изображение создано с помощью ИИ)

В js файле мы будем использовать метод document.querySelector() для получения полей ввода и формы:

const username = document.querySelector('#username');
const emailed = document.querySelector('#email');
const password = document.querySelector('#password');
const confirm Password El = document.querySelector('#confirm-password');

const form = document.querySelector('#signup');

Затем прослушиватель событий прикрепляется к форме с помощью метода addEventListener(). В прослушивателе событий нужно вызвать команду e.preventDefault() чтобы предотвратить отправку формы после нажатия кнопки.

form.addEventListener('submit', function (e) {
    // Предотвращаем обновление страницы при отправке формы
    e.preventDefault();
});

Подготовка вспомогательных функций

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

  • поле обязательным для заполнения;
  • длина вводимой информации находится в требуемом диапазоне;
  • адрес электронной почты имеет допустимый формат;
  • пароль является надёжным.

Первая функция isRequired() возвращает true, если поле формы не заполнено.

const isRequired = value => value === ‘ ‘ ? false : true;

Функция isBetween() возвращает значение false, если длина (length) введённых данных не находится в заданном диапазоне.

const isBetween = (length, min, max) => length < min || length > max ? false : true;

Чтобы проверить правильность формата электронной почты потребуется использовать регулярное выражение.

const isEmailValid = (email) => {
    const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    return re.test(email);
};

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

const isPasswordSecure = (password) => {
    const re = new RegExp("^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*])(?=.{8,})");
    return re.test(password);
};

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

Разработка функции вывода ошибок

Функция showError() выделяет border у input в красный цвет и отображает сообщение об ошибке, если введённые в поле данные недопустимы.

const showError = (input, message) => {
    // Получаем элемент с классом form-field
    const formField = input.parentElement;
    // Добавляем класс error
    formField.classList.remove('success');
    form Field.classList.add('error');

    // Показываем сообщение об ошибке
    const error = formField.querySelector('small');
    error.textContent = message;
};

Во-первых, разберёмся теперь, как это работает. Сначала мы получаем родительский элемент поля ввода, которым является <div> элемент с классом form-field.

const form Field = input.parentElement;

Во-вторых, удаляем класс success и добавляем класс error к form-field элементу.

formField.classList.remove('success');
form Field.classList.add('error');

В-третьих, выбираем элемент <small> внутри form-field элемента.

const error = form Field.querySelector('small');

Обратите внимание, что мы используем formField.querySelector() вместо document.querySelector(). Наконец, выводим сообщение об ошибке с помощью свойства textContent элемента <small>.

error.text Content = message;

Функция, отвечающая за правильность введённых данных, аналогична функции showError().

const showSuccess = (input) => {
    // Получаем элемент form-field
    const formField = input.parentElement;

    // Удаляем класс error
    formField.classList.remove('error');
    formField.classList.add('success');

    // Удаляем сообщение об ошибке
    const error = formField.querySelector('small');
    error.textContent = ' ';
}

В отличие от функции showError(), showSuccess() удаляет класс error, добавляет класс success и удаляет сообщение об ошибке.

Теперь можно использовать все рассмотренные выше вспомогательные функции для проверки каждого поля.

Функции проверки полей формы на JavaScript

Всего используются четыре функции для проверки значений полей формы.

Поле имени пользователя

Функция checkUsername() использует:

  • isRequired() для проверки, указано ли имя пользователя;
  • isBetween() для установления, составляет ли имя пользователя от 3 до 25 символов;
  • showError() и showSuccess() необходимы, чтобы показать/скрыть сообщения об ошибке.

Функция возвращает true, если поле проходит проверки:

const checkUsername = () => {

    let valid = false;
    const min = 3,
        max = 25;
    const username = username.value.trim();

    if (!isRequired(username)) {
        showError(username, 'Поле не может быть пустым!');
    } else if (!isBetween(username.length, min, max)) {
        showError(username, `Имя пользователя должно быть длиной от ${min} до ${max} символов.`)
    } else {
        showSuccess(usernameEl);
        valid = true;
    }
    return valid;
}

Поле электронной почты

Функция checkEmail() возвращает true, если адрес электронной почты введён и имеет правильный формат:

const checkEmail = () => {
    let valid = false;
    const email = email.value.trim();
    if (!isRequired(email)) {
        showError(email, 'Поле email не может быть пустым!');
    } else if (!isEmailValid(email)) {
        showError(email, 'Введите правильный email')
    } else {
        showSuccess(emailEl);
        valid = true;
    }
    return valid;
}

Ввод пароля

Функция checkPassword() проверяет поле пароля, заполнено ли оно, и соответствует ли требуемому формату:

const checkPassword = () => {

    let valid = false;

    const password = password.value.trim();

    if (!isRequired(password)) {
        showError(password, 'Поле пароля не может быть пустым!');
    } } else if (!isPasswordSecure(password)) {
        showError(password, 'Пароль должен иметь длину минимум 8 знаков, включая минимум 1 знак верхнего и 1 знак нижнего регистра, 1 цифру и 1 спецсимвол (!@#$%^&*)');
    } else {
        showSuccess(passwordEl);
        valid = true;
    }

    return valid;
};

Подтверждение пароля

Функция checkConfirmPassword() проверяет совпадение пароля с полем для его подтверждения:

const checkConfirmPassword = () => {
    let valid = false;
    // Проверяем подтверждение пароля
    const confirm Password = confirmPasswordEl.value.trim();
    const password = password.value.trim();

    if (!isRequired(confirmPassword)) {
        showError(confirm password, 'Пароль не соответствует требованиям');
    } else if (password !== confirmPassword) {
        showError(confirmPasswordEl, 'Пароли не совпадают');
    } else {
        showSuccess(confirmPasswordEl);
        valid = true;
    }

    return valid;
};

Как осуществляется валидация формы на js

Как происходит валидация формы на js (JavaScript)
Написание основного кода валидации формы (изображение создано с помощью ИИ)

Теперь можно использовать функции, которые проверяют поля формы в обработчике события отправки.

form.addEventListener('submit', function (e) {
    // Предотвращаем перезагрузку страницы при отправке формы
    e.preventDefault();

    // Проверяем правильность введённых данных в форму
    let isUsernameValid = checkUsername(),
        isEmailValid = checkEmail(),
        isPasswordValid = checkPassword(),
        isConfirmPasswordValid = checkConfirmPassword();

    let isFormValid = isUsernameValid &&
        isEmailValid &&
        isPasswordValid &&
        isConfirmPasswordValid;

    // Отправляем данные из формы, если все правильно
    if (isFormValid) {

    }
});

Как будет работать такой функционал? Сначала будет вызвана каждая отдельная функция для проверки полей имени пользователя, электронной почты, пароля и его подтверждения.

Для проверки допустимой информации в форме используется оператор &&. Данные будут направлены на сервер, если поля формы заполнены правильно. В силу того для этого потребуется использовать флаг isFormValid.

Стоит отметить, что на текущий момент форма показывает ошибку или правильность введённых данных только при нажатии кнопки отправки. Чтобы обеспечить мгновенную обратную связь, можно прикрепить прослушиватель событий к событию каждого поля и проверять его. Ещё лучше использовать делегирование событий, чтобы прикрепить прослушиватель событий с целью проверки каждого поля на основе id каждого input.

form.addEventListener('input', function (e) {
    switch (e.target.id) {
        case 'username':
            checkUsername();
            break;
        case 'email':
            checkEmail();
            break;
        case 'password':
            checkPassword();
            break;
        case 'confirm-password':
            checkConfirmPassword();
            break;
    }
});

Теперь, если ввести любые данные, форма обратной связи мгновенно отображает либо ошибку, либо её отсутствие. Кроме того, это повышает производительность функционала.

Технически, необходимо будет подождать, пока пользователи приостановят ввод текста на небольшое время или прекратят печатать, прежде чем проверить введённые данные. Как это работает?

Ниже показана функция debounce():

const debounce = (fn, delay = 500) => {
    let timeoutId;
    return (...args) => {
        // Остановка предыдущего таймера
        if (timeout) {
            clearTimeout(timeoutId);
        }
        // Запуск нового таймера
        timeoutId = setTimeout(() => {
            fn.apply(null, args)
        }, delay);
    };
};

Теперь можно передать обработчик события в debounce().

form.addEventListener('input', debounce(function (e) {
    switch (e.target.id) {
        case 'username':
            checkUsername();
            break;
        case 'email':
            checkEmail();
            break;
        case 'password':
            checkPassword();
            break;
        case 'confirm-password':
            checkConfirmPassword();
            break;
    }
}));

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

Итоговый код

Теперь мы можем объединить весь написанный нами JavaScript код:

const usernameEl = document.querySelector('#username');
const emailEl = document.querySelector('#email');
const passwordEl = document.querySelector('#password');
const confirmPasswordEl = document.querySelector('#confirm-password');

const form = document.querySelector('#signup');


const checkUsername = () => {

    let valid = false;

    const min = 3,
        max = 25;

    const username = usernameEl.value.trim();

    if (!isRequired(username)) {
        showError(usernameEl, 'Поле не может быть пустым!');
    } else if (!isBetween(username.length, min, max)) {
        showError(usernameEl, `Имя пользователя должно быть длиной от ${min} до ${max} символов.`)
    } else {
        showSuccess(usernameEl);
        valid = true;
    }
    return valid;
};


const checkEmail = () => {
    let valid = false;
    const email = emailEl.value.trim();
    if (!isRequired(email)) {
        showError(emailEl, 'Поле не может быть пустым!');
    } else if (!isEmailValid(email)) {
        showError(emailEl, 'Проверьте правильность email')
    } else {
        showSuccess(emailEl);
        valid = true;
    }
    return valid;
};

const checkPassword = () => {
    let valid = false;


    const password = passwordEl.value.trim();

    if (!isRequired(password)) {
        showError(passwordEl, 'Поле не может быть пустым!');
    } else if (!isPasswordSecure(password)) {
        showError(passwordEl, 'Пароль должен иметь длину минимум 8 знаков, включая 1 знак верхнего и 1 знак нижнего регистра, 1 цифру и 1 спецсимвол (!@#$%^&*)');
    } else {
        showSuccess(passwordEl);
        valid = true;
    }

    return valid;
};

const checkConfirmPassword = () => {
    let valid = false;
    // Проверка паролей на совпадение
    const confirmPassword = confirmPasswordEl.value.trim();
    const password = passwordEl.value.trim();

    if (!isRequired(confirmPassword)) {
        showError(confirmPasswordEl, 'Введите пароль заново!');
    } else if (password !== confirmPassword) {
        showError(confirmPasswordEl, 'Пароли не совпадают');
    } else {
        showSuccess(confirmPasswordEl);
        valid = true;
    }

    return valid;
};

const isEmailValid = (email) => {
    const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
    return re.test(email);
};

const isPasswordSecure = (password) => {
    const re = new RegExp("^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[!@#\$%\^&\*])(?=.{8,})");
    return re.test(password);
};

const isRequired = value => value === '' ? false : true;
const isBetween = (length, min, max) => length < min || length > max ? false : true;


const showError = (input, message) => {
    // Получаем элемент с классом form-field
    const formField = input.parentElement;
    // Добавляем класс error
    formField.classList.remove('success');
    formField.classList.add('error');

    // Показываем сообщение об ошибке
    const error = formField.querySelector('small');
    error.textContent = message;
};

const showSuccess = (input) => {
    // Получаем элемент с классом form-field
    const formField = input.parentElement;

    // Удаляем класс error
    formField.classList.remove('error');
    formField.classList.add('success');

    // Убираем сообщение об ошибке
    const error = formField.querySelector('small');
    error.textContent = '';
}


form.addEventListener('submit', function (e) {
    // Предотвращаем перезагрузку страницы при отправке формы
    e.preventDefault();

    // Проводим валидацию полей формы
    let isUsernameValid = checkUsername(),
        isEmailValid = checkEmail(),
        isPasswordValid = checkPassword(),
        isConfirmPasswordValid = checkConfirmPassword();

    let isFormValid = isUsernameValid &&
        isEmailValid &&
        isPasswordValid &&
        isConfirmPasswordValid;

    // Отправка данных формы, если валидация пройдена
    if (isFormValid) {

    }

    // Выводим в консоль данные формы
    console.log(username.value);
    console.log(email.value);
    console.log(password.value);
    console.log(confirmPasswordEl.value);
  
    // Очищаем форму после отправки
    e.target.reset();
});


const debounce = (fn, delay = 500) => {
    let timeoutId;
    return (...args) => {
        // Останавливаем предыдущий таймер
        if (timeoutId) {
            clearTimeout(timeoutId);
        }
        // Запускаем новый таймер
        timeoutId = setTimeout(() => {
            fn.apply(null, args)
        }, delay);
    };
};

form.addEventListener('input', debounce(function (e) {
    switch (e.target.id) {
        case 'username':
            checkUsername();
            break;
        case 'email':
            checkEmail();
            break;
        case 'password':
            checkPassword();
            break;
        case 'confirm-password':
            checkConfirmPassword();
            break;
    }
}));

See the Pen
Untitled
by Вячелав Демченко (@upsdjzqs-the-reactor)
on CodePen.