Валидация формы с помощью AJV, Vue.js и TypeScript

от автора

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

Что такое AJV?

AJV (Another JSON Schema Validator) — это быстрая библиотека валидации данных в формате JSON с поддержкой JSON Schema. JSON Schema — это язык описания структуры и валидации данных в формате JSON. AJV позволяет проверять данные по подготовленным схемам валидации.

Подготовка проекта

Прежде чем начать, убедитесь, что у вас уже есть:

  1. Node.js v18.16.1.

  2. @vue/cli 5.0.8

Давайте создадим проект новый проект с помощью Vue CLI с такими параметрами:

vue create ajv-validation

Установим необходимые зависимости в нашем проекте:

npm install ajv ajv-formats ajv-errors

Создание файла схемы валидации login.json

login.json
{   "$id": "/login.json",   "type": "object",   "additionalProperties": false,   "required": ["login", "password"],   "properties": {     "login": {       "type": "string",       "format": "email",       "errorMessage": "enter a valid email address"     },     "password": {       "type": "string",       "minLength": 6,       "maxLength": 1024     }   } }

В этой схеме мы определяем тип каждого поля (строка), а также устанавливаем некоторые правила валидации, такие как формат email и минимальная длина пароля. Поля «login» и «password» обязательны для заполнения.

Давайте кратко пройдёмся по 2 важным методам:

onLogin — это метод, который вызывается при попытке входа пользователя в систему (логине). Он выполняет проверку и валидацию введенных пользователем данных и предпринимает соответствующие действия в зависимости от результата проверки.

  1. Проверка введенных данных на корректность с помощью функции валидации validate. Эта функция использует схему валидации данных и проверяет соответствие данных этой схеме. Возвращается флаг isValid, который указывает, прошла ли валидация успешно.

  2. Если данные некорректны (isValid равен false), выполняется обработка ошибок.

function onLogin()
function onLogin() {       errors.value.clear();       if (validator.validate("/login.json", formData.value)) {         // valid, do nothing       } else if (validator.errors?.length) {         for (const [, e] of validator.errors.entries()) {           if (!e.message) {             continue;           }           const fieldName = e.instancePath.substring(1);           const fieldErrors: string[] = errors.value.get(fieldName) || [];           fieldErrors.push(e.message);           errors.value.set(fieldName, fieldErrors);         }       }     }

onBlur — это метод, который вызывается при событии «blur» (потеря фокуса) на текстовом поле ввода формы. Он используется для валидации данных, введенных пользователем, когда пользователь переходит с поля на другой элемент формы или щелкает вне текстового поля.

  1. Получить имя (идентификатор) и значение поля ввода, на котором произошло событие «blur».

  2. Получить схему валидации для данного поля.

  3. Проверка значения поля на корректность с помощью функции валидации validate.

  4. Если значение поля некорректно (isValid равен false), выполняется обработка ошибки.

function onBlur()
function onBlur(e: any) {       const fieldName = e.target.id;       const fieldValue = e.target.value;       if (         validator.validate(`/login.json#/properties/${fieldName}`, fieldValue)       ) {         errors.value.delete(fieldName);       } else if (validator.errors?.length) {         errors.value.set(           fieldName,           validator.errors.map((e) => e.message) as string[]         );       }     }

Заключение

Теперь у вас есть пример, как использовать AJV с Vue.js и TypeScript для валидации формы. Это позволяет создавать мощные и гибкие системы валидации, которые помогут улучшить пользовательский опыт и обеспечить корректную обработку данных на сервере.

Исходный код

App.vue
<template>   <div class="login-form">     <h2>Login</h2>     <form @submit.prevent="onLogin">       <div class="form-group">         <label for="login">Email</label>         <input           v-model="formData.login"           :class="{ 'is-invalid': isInvalid(errors.has('login')) }"           @blur="onBlur"           type="text"           id="login"           placeholder="Enter your email"         />         <ul class="error-wrapper">           <li v-for="errorMsg of errors.get('login')" :key="errorMsg">             {{ errorMsg }}           </li>         </ul>       </div>        <div class="form-group">         <label for="password">Password</label>         <input           v-model="formData.password"           :class="{ 'is-invalid': isInvalid(errors.has('password')) }"           @blur="onBlur"           type="password"           id="password"           placeholder="Enter your password"         />          <ul class="error-wrapper">           <li v-for="errorMsg of errors.get('password')" :key="errorMsg">             {{ errorMsg }}           </li>         </ul>       </div>        <button type="submit" :disabled="errors.size > 0" @click="submit('ok')">         Login       </button>     </form>   </div> </template>  <script lang="ts"> import { defineComponent, ref, watch } from "vue"; import login from "@/schemas/login.json"; import Ajv from "ajv"; import ajvFormats from "ajv-formats"; import ajvErrors from "ajv-errors";  export default defineComponent({   setup() {     const formData = ref({       login: "",       password: "",     });      const opts = { allErrors: true };     const validator = ajvErrors(ajvFormats(new Ajv(opts)));     validator.addSchema(login);      let errors = ref<Map<string, string[]>>(new Map());     watch(       () => errors.value,       () => void 0     );      function onBlur(e: any) {       const fieldName = e.target.id;       const fieldValue = e.target.value;       if (         validator.validate(`/login.json#/properties/${fieldName}`, fieldValue)       ) {         errors.value.delete(fieldName);       } else if (validator.errors?.length) {         errors.value.set(           fieldName,           validator.errors.map((e) => e.message) as string[]         );       }     }      function onLogin() {       errors.value.clear();       if (validator.validate("/login.json", formData.value)) {         // valid, do nothing       } else if (validator.errors?.length) {         for (const [, e] of validator.errors.entries()) {           if (!e.message) {             continue;           }           const fieldName = e.instancePath.substring(1);           const fieldErrors: string[] = errors.value.get(fieldName) || [];           fieldErrors.push(e.message);           errors.value.set(fieldName, fieldErrors);         }       }     }      function formColor(error: any) {       return error?.length;     }      function submit(text: string) {       alert(text);     }      return {       formData,       errors,       isInvalid: formColor,       onBlur,       onLogin,       submit,     };   }, }); </script>  <style> body {   font-family: sans-serif; }  .login-form {   max-width: 300px;   margin: 0 auto;   padding: 20px;   border: 1px solid #ccc;   border-radius: 5px;   background-color: #f9f9f9; }  .login-form h2 {   text-align: center;   margin-bottom: 20px; }  .form-group {   margin-bottom: 20px; }  label {   display: block;   font-weight: bold;   margin-bottom: 5px; }  input {   width: 100%;   padding: 8px;   border: 1px solid #ccc;   border-radius: 5px; }  button {   width: 100%;   padding: 10px;   background-color: #007bff;   color: #fff;   border: none;   border-radius: 5px;   cursor: pointer;   transition: background-color 0.3s ease; }  button:hover {   background-color: #0056b3; }  button:disabled {   background-color: #ccc; }  .is-invalid {   border: 1px solid red; }  .error-wrapper {   color: red;   font-size: 12px;   margin: 0;   padding: 0 20px; } </style> 

github


ссылка на оригинал статьи https://habr.com/ru/articles/752074/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *