التحقّق من الصحة على مستوى النموذج (Form Level Validations)
الدرس 8 من 21 · دورة TanStack Form الكاملة · 7 دقيقة و43 ثانية
الفيديو الأصلي باللغة الإنجليزية. إذا تعذّر تشغيله هنا، شاهده على موقع المؤلف. التفريغ النصي العربي الكامل أدناه.
مستودع شيفرة هذا الدرس
الفرع:
validation-2
[00:01] كما ذكرنا، وبالإضافة إلى إجراء التحقّق من الصحة (validation) على مستوى الحقل (field)، يمكننا أيضًا إجراء التحقّق من الصحة على مستوى النموذج (form) كذلك. ففي هنا، عندما نُعرّف نموذجنا باستخدام useForm، يمكننا أيضًا إضافة validators هنا. غير أنّن نحتاج إلى
[00:16] أن نميّز بين شيئين. يلزمنا التمييز بين الأخطاء التي سنعيدها كخطأ عام للنموذج بأكمله، وبين الأخطاء التي تنتمي إلى حقل معيّن. ففي هنا — عذرًا — هذا كائن (object) وليس
[00:31] دالة، وفي هنا يمكننا أن نمرّر إليه الأشياء نفسها التي يمكننا تمريرها في مستوى الحقل: onChange وonBlur وما إلى ذلك. فلنفعل onChange مثلًا. فالآن، في هذه الدالة، ما سنحصل عليه كقيمة هو قيمة
[00:45] النموذج بأكمله لا حقل معيّن. فلنجرّب ربما طباعة هذا عبر console.log.
[00:50] ويجب أن يحتوي هذا على قيم جميع حقولنا. وكذلك في هنا — بالمناسبة — فلنحذف هذا الكائن الذي نعرضه هنا.
[01:01] والآن إذا ذهبنا إلى console لدينا وغيّرنا ربما شيئًا هنا، فنتيجة هذا console.log في محقّق onChange لدينا، وهو في السطر 64 هنا، فإنّنا — نحن — نحصل على قيم نموذجنا بأكمله.
[01:16] إذًا ما يمكننا فعله هنا هو أننا نستطيع التحقّق من أيّ حقل يلزمنا التحقّق منه.
[01:19] فلنقل — عذرًا — بالمناسبة، فقط كي نتجنّب أيّ التباس، فلنُعلّق (comment) validators مستوى الحقل مؤقتًا ونُبقي واحدًا فقط على مستوى النموذج. وفي هنا يمكننا التحقّق ربما أيضًا من الاسم الأول. إذًا value
[01:34] firstName، وفلنفعل التحقّق نفسه الذي فعلناه. إذا لم يكن الاسم الأول John، فسنعيد «your name must be John». غير أنّه فلنجري تحديثًا (refresh). وعندما نعيد بعض الخطأ في validators المُعرَّف
[01:49] على مستوى النموذج، فما سنعيده هنا سيكون خطأ عامًا للنموذج، ولن يكون مرتبطًا بحقل معيّن. فإذا كتبنا هنا شيئًا ليس John، فلنحصل على خطأ ليس لهذا
[02:02] الحقل، لأنّ هذا ليس خطأ لهذا الحقل؛ بل هو خطأ عام للنموذج. وكيف يمكننا الوصول إلى هذا؟ يمكننا الوصول إليه في حالة (state) النموذج ذاتها، وهي — كما نعرف الآن — الحالة التي يمكننا الاشتراك في أشيائها
[02:15] من النموذج باستخدام المخزن (store)، وكذلك باستخدام form.subscribe. لكن هذه المرة فلنشترك في أخطاء النموذج باستخدام الخُطّاف (hook) useStore. وفي هنا يمكننا بتمرير الـstore form.store، وفي حالة النموذج لدينا إمكانية
[02:32] الوصول إلى أخطاء.
[02:35] هذه الأخطاء هي أخطاء عامة للنموذج أعُدّها من هنا، ولا هي أخطاء متعلّقة بحقل معيّن. فسأعرض هذه الأخطاء فقط قبل تصيير النموذج لأنّها لا تتعلّق بحقل
[02:48] معيّن. ويمكننا وضع هذه الأخطاء قبل النموذج هكذا. والآن إذا تأملنا، فكلّما كتبنا سنحصل على هذا الخطأ، وهو خطأ عام للنموذج وليس خطأ مربوطًا بحقل معيّن. غير أنّه هذا لا يعني أنّه
[03:04] في كائن validators الذي نُعرّفه في useForm على مستوى النموذج، لا يمكننا إعادة أخطاء متعلّقة بحقول معيّنة؛ فبإمكاننا فعل ذلك كذلك. فلنقل ربما أنّنا نحذف هذا التحقّق هنا، ونقول
[03:19] إنّنا نحتاج إلى إعادة خطأ ينتمي إلى الاسم الأول بحيث يظهر بعد الاسم الأول، منذ أنّنا — تذكّر — نعرض الأخطاء هنا بعد حقل input الخاص بالاسم الأول. فلنقل إنّنا نحتاج إلى تعبئة أخطاء هذا
[03:32] الاسم الأول. فما يمكننا فعله هو أنّه بدلًا من إعادة الخطأ وحده، يمكننا إعادة كائن يحتوي على الحقول (fields).
[03:40] إذًا return، وفي هنا نعيد كائنًا يحتوي على fields، وفي fields يمكننا إذًا اختيار حقل كالاسم الأول مثلًا وإعادة خطأ للاسم الأول. فلنكتب ربما هنا بعض الأشياء العشوائية ونحفظ. الآن فلن
[03:58] نجري تحديثًا.
[04:00] وبينما نكتب هنا سنحصل على هذا الخطأ. والآن هذا الخطأ متعلّق بالاسم الأول منذ أنّنا نعيد كائن fields هذا هنا. لكن الآن يمكننا فعل أشياء حقيقية هنا. فسأقوم فقط بعمل واحد سريع هنا. نقول ربما أن نتحقق: إذا لم تكن
[04:14] value — ويتذكّر أنّ value هي قيمة نموذجنا بأكمله — فإذا لم يكن لدينا value.firstName، فلنعد first name is required. نحفظ هذا. نجري تحديثًا. والآن بينما نكتب ونحذف اسمنا الأول، يجب أن نحصل على first name is required. إذًا
[04:29] من هنا يمكننا أيضًا استهداف حقول معيّنة.
[04:32] والآن قد تتساءل: كيف نستهدف الحقول المتشعّبة (nested) مثل حقل street هذا مثلًا؟ وببساطة شديدة يمكننا هنا استخدام النقاط مجددًا. إذًا address
[04:46] street مثلًا. فلنقل إنّنا نحتاج إلى إعادة خطأ لهذا. فيمكننا الآن أن نفعل ذلك فحسب. وسأجري أيضًا فحصًا سريعًا هنا: إذا لم نمتلك value.address.street فنعيد خطأً. غير أنّه — تذكّر — أنّنا نعرض فقط
[05:01] الأخطاء لهذا المدخل الذي ينتمي إلى حقل الاسم الأول. ويتعين علينا أن نفعل الشيء نفسه لبقية حقولنا كذلك.
[05:09] إذًا سأنسخ هذا المقطع من الشيفرة الذي يعرض الخطأ وأضعه أيضًا لحقل street، وهو هذا.
[05:19] ولا تقلق؛ فأعلم أنّ هذا بعض موضع التكرار، لكننا لاحقًا سننظّف الأمور ونجعل نموذجنا قابلاً لإعادة الاستخدام (reusable) بدرجة أكبر. لكن فلنضع هذا هنا في الوقت الحالي.
[05:29] والآن إذا كتبنا وحذفنا، يجب أن نحصل على هذا الخطأ لحقل street كذلك.
[05:34] ويمكننا فعل ذلك للمصفوفات كذلك. فسنعود هنا إلى validators في useForm لدينا، لحقولنا. تذكّر أنّه لدينا مصفوفة (array) مهارات، وكل مهارة كائن يحتوي على اسم المهارة، وID، ومستوى. فلن
[05:50] نقل إنّنا نحتاج إلى إعادة خطأ لمدخل مستوى لأول عنصر (item) في مصفوفة مهاراتنا. ويمكننا فعل ذلك بإضافة skills[0] هنا مثلًا. ثم إنّ هذا كائن؛ نحتاج عنصر level في هذا الكائن. وبالنسبة إلى هذا
[06:08] المستوى، يمكننا ربما أيضًا إجراء فحص: إذا لم تكن value.skills[0].level لدينا هي expert مثلًا، فلنعد خطأً ما كذلك. فسأعيد you must be an expert، وإلا فأعيد undefined وهذا يعني أنّ
[06:25] لا توجد أخطاء.
[06:28] وكما سبق، لا نعرض أخطاءً لهذا dropdown. فلنفعل ذلك بسرعة هنا. فلننسخ هذا المقطع من الشيفرة.
[06:35] وتذكّر أنّ هذا dropdown كان في هذا الحقل الفرعي الذي نمرّ عليه بحلقة (loop). هنا عندها dropdown لدينا. ففي هنا بعد select لدينا، فلنغلّف select لدينا ضمن مجمّع (fragment) ما أو ما يشابهه.
[06:56] ثم فلنضع هذا هنا.
[06:56] غير أنّه — تذكّر — يستوجب أن يكون الآن sub field وليس field هكذا. فأعتذر؛ فليدينا في هنا تشعّب كثير. لكن هذا ينبغي أن يعمل.
[07:06] إذا غيّرنا شيئًا هنا ولم نختر expert، يجب أن نحصل على هذا الخطأ أيضًا: You must be an expert.
[07:16] إذًا لدينا الخياران معًا. يمكننا إجراء تحقّقاتنا على مستوى الحقل، لكن يمكننا أيضًا إجراؤها على مستوى النموذج كذلك. غير أنّه ثمة شيء ينبغي أن تدركه إذا امتلكت الاثنين، إذا امتلكت تحقّقاتً تحدث على
[07:30] النموذج هنا وقد أعدتَ ربما خطأً للاسم الأول، ثم في الاسم الأول نفسه لديك validators ولديك خطأ من هنا كذلك، فإحداكما سيتجاوز الآخر القادم من مستوى النموذج في TanStack Form. ويمكنك