דוגמת קוד: בדיקת טופס עם yup ב vue
הדרך הכי קלה היום לעבוד עם טפסים היא לדלג עליהם בספריית ה SPA שלנו, ולהשתמש במאפייני ה HTML ו ValidityState של רכיבי הקלט כדי להציג הודעות למשתמשים. ועדיין לפעמים אנחנו צריכים בדיקות יותר מסובכות או שרוצים להריץ תהליך יותר מסודר סביב הנושא של בדיקות קלט בצד לקוח. במצבים כאלה נוכל להשתמש בספריה כמו yup כדי לתאר את הטופס ובקוד לעדכן את הודעות השגיאה בתוך אפליקציית vue או ריאקט. בואו נראה איך זה עובד.
1. סכימת yup
ספריית yup היא ספריית וולידציה למידע שמאפשרת להריץ בדיקות ולבצע המרות על קלט שקיבלה. יש לה המון אופציות איך להגדיר את הקלט ואנחנו ניקח כאן דוגמה פשוטה עבור טופס רישום שמקבל כתובת אימייל וסיסמה, שניהם הכרחיים ואורך הסיסמה צריך להיות לפחות 8 תווים. זה הקוד כדי ליצור את הסכימה עם yup:
import {object, string} from 'yup';
export const signupFormSchema = object({
email: string()
.email()
.required(),
password: string()
.min(8, 'password must be at least 8 characters long')
.required(),
});
סכימה של yup יודעת לקבל אוביקט ולהגיד אם הוא מתאים או לא בעזרת פונקציה אסינכרונית בשם validate
. לדוגמה הקוד הבא:
try {
await signupFormSchema.validate({email: 'ynon@demo.com', password: '12345678'});
console.log('OK');
} catch (err) {
console.log(err);
}
מדפיס את ההודעה OK, אבל הקוד הזה מדפיס הודעת שגיאה כי הסיסמה קצרה מדי:
try {
await signupFormSchema.validate({email: 'ynon@demo.com', password: '123'});
console.log('OK');
} catch (err) {
console.log(err);
}
2. חיבור הסכימה לטופס
חיבור הסכימה לטופס הוא הסיבה שאני מעדיף כמעט תמיד להשתמש בפקודות המובנות ב HTML על פני קוד, במיוחד בעבודה עם ספריות SPA. אלה הדברים שהייתי צריך לעשות ב vue בשביל החיבור (וכן אני יודע שיש ספריות שיעשו את החיבור הזה בשבילי. להחביא קוד בתוך ספריה לא מעלים אותו):
הגדרתי משתנה ריאקטיבי שישמור את השגיאות.
הגדרתי משתנה ריאקטיבי נוסף שישמור את מצב ההגשה של הטופס (אם כבר הגשתי אותו או לא).
הגדרתי פונקציה לטפל באירוע submit של הטופס ולבצע וולידציה על המידע שבטופס.
הוספתי אלמנטי HTML להצגת הודעות השגיאה.
סך הכל קוד הטופס ב vue הוא:
<script setup lang="ts">
import {signupFormSchema} from '../schemas/signup1';
import { ValidationError } from 'yup';
import {computed, ref, Ref} from 'vue';
const errors = ref<Array<ValidationError>>([]);
const status = ref<'pending'|'submitted'>('pending');
const errorsObject: Ref<Record<string, Array<ValidationError>>> = computed(() =>
Object.groupBy(errors.value, e => e.path))
async function signup(ev: Event) {
const form = ev.target as HTMLFormElement;
const fd = new FormData(form);
const data = Object.fromEntries(fd);
try {
await signupFormSchema.validate(data, {abortEarly: false})
errors.value = [];
status.value = 'submitted';
} catch (err) {
if (err instanceof ValidationError) {
errors.value = err.inner;
console.log(err.inner);
} else {
throw err
}
}
}
</script>
<template>
<div v-if="status == 'submitted'">
Ready!
</div>
<form @submit.prevent="signup">
<div class="errors" v-if="errors.length > 0">
<h3>Form Erorrs:</h3>
<ul >
<li
v-for="(error, index) in errors"
:key="index"
>
{{ error.message }}
</li>
</ul>
</div>
<div>
<label>
<span>Email: </span>
<input name="email" type="email" />
</label>
</div>
<div>
<label>
<span>
Password:
</span>
<input name="password" type="password" />
</label>
</div>
<div>
<input type="submit" value="Signup" :disabled="status === 'submitted'" />
</div>
</form>
</template>
<style scoped>
label > span {
width: 100px;
display: inline-block;
}
form > div {
text-align: left;
margin: 10px;
}
.errors {
text-align: left;
list-style: none;
padding-left: 10px;
}
</style>
3. מסקנות
וולידציית קלטים בצד לקוח זה תמיד כאב ראש אבל זה רק נהיה יותר מעייף כשצריך לחבר בין הוולידציה לספריית SPA. ספריות קוד לטיפול אוטומטי בדברים האלה קיימות אבל האמת שבלי קוד תמיד עדיף על קוד שמוחבא בתוך ספרייה. שימוש בפקודות המובנות ב HTML חוסך אלמנטים עודפים ב DOM וחוסך משתנים ריאקטיביים וכך גם עבודת JavaScript.
ומה אתכם? איך אתם אוהבים לנהל את הטפסים שלכם? אל תתביישו לשתף בתגובות או בטלגרם.