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

Асинхронная валидация в Element Plus позволяет выполнять проверки данных формы не только на стороне клиента, но и обращаться к серверу или выполнять сложные вычисления перед подтверждением корректности ввода. Это особенно важно для проверок, которые не могут быть выполнены мгновенно, например, проверка уникальности имени пользователя или валидность токена.


Использование async validator

Основной инструмент для асинхронной валидации — это функция validator, возвращающая Promise. В отличие от синхронной проверки, где возвращается true или false, асинхронная функция использует промис, который разрешается при успешной валидации или отклоняется с сообщением об ошибке.

Пример:

import { reactive } from 'vue';

const rules = reactive({
  username: [
    { 
      required: true, 
      message: 'Имя пользователя обязательно', 
      trigger: 'blur' 
    },
    {
      validator: async (rule, value) => {
        if (!value) return Promise.resolve();
        const response = await fetch(`/api/check-username?username=${value}`);
        const data = await response.json();
        if (data.exists) {
          return Promise.reject('Имя пользователя уже занято');
        }
        return Promise.resolve();
      },
      trigger: 'blur'
    }
  ]
});

Ключевые моменты:

  • Асинхронный validator всегда принимает два аргумента: rule и value.
  • Возвращаемый объект должен быть Promise.
  • Promise.reject('сообщение') прерывает валидацию и выводит сообщение об ошибке.
  • Promise.resolve() подтверждает корректность значения.

Комбинирование синхронной и асинхронной валидации

Часто требуется объединять базовые проверки (например, обязательное поле) с асинхронной проверкой. Element Plus поддерживает последовательное выполнение правил. Сначала выполняются синхронные проверки, затем асинхронные.

Пример комбинирования:

const rules = reactive({
  email: [
    { 
      required: true, 
      message: 'Email обязателен', 
      trigger: 'blur' 
    },
    {
      type: 'email', 
      message: 'Некорректный формат email', 
      trigger: ['blur', 'change'] 
    },
    {
      validator: async (rule, value) => {
        const res = await fetch(`/api/check-email?email=${value}`);
        const data = await res.json();
        if (data.exists) {
          return Promise.reject('Email уже зарегистрирован');
        }
        return Promise.resolve();
      },
      trigger: 'blur'
    }
  ]
});

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

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

Пример:

import { ref } from 'vue';

const formRef = ref(null);
const formData = reactive({ username: '', email: '' });

async function submitForm() {
  try {
    await formRef.value.validate();
    console.log('Форма валидна, можно отправлять данные на сервер');
  } catch (err) {
    console.log('Ошибка валидации:', err);
  }
}

Особенности:

  • validate проверяет все поля формы, включая асинхронные.
  • Ошибки асинхронных валидаторов автоматически добавляются в состояние формы.
  • Метод resetFields() позволяет очистить ошибки и вернуть форму к исходному состоянию.

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

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

Пример с использованием lodash.debounce:

import debounce from 'lodash/debounce';

const checkUsername = debounce(async (value) => {
  const response = await fetch(`/api/check-username?username=${value}`);
  const data = await response.json();
  if (data.exists) throw new Error('Имя пользователя уже занято');
}, 500);

const rules = reactive({
  username: [
    {
      validator: async (rule, value) => {
        if (!value) return Promise.resolve();
        try {
          await checkUsername(value);
        } catch (err) {
          return Promise.reject(err.message);
        }
      },
      trigger: 'blur'
    }
  ]
});

Преимущества:

  • Сокращает количество сетевых запросов.
  • Предотвращает лишнюю нагрузку на сервер при быстром вводе.
  • Поддерживает полное управление ошибками через стандартный интерфейс Element Plus.

Асинхронная валидация для динамических форм

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

Пример с массивом пользователей:

const users = reactive([
  { name: '', rules: [] },
]);

function addUser() {
  users.push({
    name: '',
    rules: [
      {
        validator: async (rule, value) => {
          const res = await fetch(`/api/check-username?username=${value}`);
          const data = await res.json();
          if (data.exists) return Promise.reject('Имя пользователя уже занято');
          return Promise.resolve();
        },
        trigger: 'blur'
      }
    ]
  });
}

Практические рекомендации

  • Использовать асинхронные проверки только там, где это необходимо. Чрезмерное количество сетевых запросов замедляет форму.
  • Обрабатывать ошибки сети отдельно. Пример: если сервер недоступен, можно выводить общее сообщение типа «Не удалось проверить значение».
  • Комбинировать синхронные проверки для базовой валидации (обязательные поля, формат) и асинхронные для сложных условий.
  • Следить за уникальностью правил при динамическом создании полей. Каждое поле должно иметь собственный экземпляр validator.

Асинхронная валидация в Element Plus обеспечивает гибкость и точность проверки данных, позволяя сочетать клиентские и серверные проверки в одной форме. Это критически важно для современных приложений с динамическими формами и высокими требованиями к корректности пользовательского ввода.