دورة TanStack Form الكاملة › دورة TanStack Form الكاملة 1 / 1 السابق التالي

التحقّق من الصحة على مستوى الحقل (Field Level Validations)

الدرس 7 من 21 · دورة TanStack Form الكاملة · 9 دقيقة و5 ثانية

الفيديو الأصلي باللغة الإنجليزية. إذا تعذّر تشغيله هنا، شاهده على موقع المؤلف. التفريغ النصي العربي الكامل أدناه.

مستودع شيفرة هذا الدرس

الفرع: validation-1

[00:02] أن نتحقّق من صحة حقولنا في TanStack Form. ففي TanStack Form، يمكننا إجراء التحقّق من الصحة (validation) على مستوى الحقل (field) لكل حقل على حِدة، أو أن نجريه على مستوى النموذج (form) كذلك أيضًا.

[00:13] وسنرى كيفية فعل الاثنين.

[00:14] غير أنّه فلنبدأ أولًا ربما بمستوى الحقل. فلنقل إذًا إنّنا نحتاج إلى التحقّق من صحة حقل الاسم الأول هذا هنا.

[00:22] وعندها، ما يمكننا فعله ببساطة هو إضافة خاصية (prop) validators هنا. ويمكننا أن نتحقّق، أو يمكننا أن نختار تمامًا متى نُجري تحقّقنا من الصحة. فليدينا في هنا onChange. وفلدينا onBlur. ولدينا أيضًا onSubmit عندما نُرسل

[00:37] نموذجنا. ويمكننا أيضًا أن نفعل هذا ديناميكيًّا (dynamically) باستخدام onDynamic وهو ما سنناقشه لاحقًا كذلك أيضًا. غير أنّه في الوقت الحالي، فلنقل إنّنا نحتاج إلى إجراء تحقّقنا باستخدام onChange عندما نغيّر حقولنا، أو أثناء كتابتنا في حقولنا. فليُضَف

[00:50] onChange هنا. وكذلك يمكن أن يكون التحقّق من الصحة متزامنًا (synchronous) أو غير متزامن (asynchronous).

[00:55] فلنقل مثلاً أنّه في بعض الحالات قد نحتاج، كي نتحقّق من صحة حقلنا، إلى إرسال طلبٍ ما عبر الشبكة. وهذا مدعوم أيضًا في TanStack Form باستخدام onChangeAsync وonBlurAsync وonSubmitAsync وما إلى ذلك. وسنطّلع

[01:09] على ذلك لاحقًا كذلك. غير أنّه في الوقت الحالي فلنركّز على التحقّق الأساسي باستخدام دالة onChange هنا. فالآن، في هذه الدالة سنمرّر — عذرًا — سنتلقّى وسيطًا هنا متضمّنًا قيمتنا. فبإمكاننا

[01:22] أن نُفكّك (destructure) قيمتنا من هنا وسنحصل هكذا على قيمتنا، ويمكننا في هنا أن نكتب منطقًا (logic) ما من أجل التحقّق من صحة هذا الحقل. فلنقل مثلًا في هنا إنّنا نحتاج إلى أن يكون حقلنا مكونًا من حرفَين على الأقل. فيمكننا

[01:36] أن نفحص هنا إذا كانت value.length لدينا ربما أقل من اثنين، فيمكننا أن نعيد شيئًا ما، وإذا أعادنا هنا شيئًا ليس false، فسيُعَدّ ذلك خطأً. فيمكننا ببساطة أن نعيد سلسلة نصّية تضمّ

[01:53] رسالة خطأ مثلًا، فسأعيد في هنا هذه الرسالة: first name must be at least two characters. والآن بعد حفظ هذا، فلنتذكّر كذلك أنّنا كنّا في حقولنا نعرض معلومات meta الخاصة بحقولنا؛ فلنُعِد

[02:07] ربما إظهار هذا كي نراه. وكما ترى بخصوص هذا الحقل، فلدينا errors. وفلدينا كذلك errorMap وerrorSourceMap وما إلى ذلك. وسيتضمّن هذا معلوماتٍ عن أخطائنا. فالآن، وقد صرنا نجري

[02:21] تحقّقنا من الصحة عبر onChange، فالآن كلّما كتبنا في هنا ينبغي أن نحصل على رسائل أخطائنا إذا كانت لَدَينا أيّ أخطاء تحقّق. وفي حالتنا لدينا هنا حرف واحد، فسنحصل من errors لدينا على مصفوفة (array) تضمّن أخطاءنا. وستكون مصفوفة لأنّنا

[02:32] يمكن أن نمتلك أخطاءً متعددة كذلك أيضًا. وكذلك سنحصل على errorMap هذا، وهو يتضمّن الدالة التي أدّت إلى هذا الخطأ، وهي في حالتنا onChange، ورسالة الخطأ، لأنّه يمكننا أيضًا امتلاك دوالّ (functions) متعددة هنا. يمكننا أن نمتلك

[02:47] تحقّقات تُجرى عبر onChange، وتحقّقات تُجرى عبر onBlur كذلك أيضًا.

[02:51] وسنحصل في errorMap هذا على الخطأ الذي حدث وأيّ دالة حَدَث به. غير أنّه الآن إذا واصلنا الكتابة فلنمتلك بعد أخطاء. فستختفي هذه الأخطاء.

[03:05] صحيح؟ فالآن بعد أن نمتلك ذلك، لماذا لا نعرض هذا الخطأ بعد الحقل؟ فبعد input لدينا، عندما نعرض مدخلنا هنا، فلنضيف شرطًا ونفحص إذا كنّا نمتلك أيّ أخطاء. فلنعرضه بكيفية ما. فبالإضافة

[03:18] إلى هذه الأخطاء سنتلقّى أيضًا الخاصية isValid هنا، وستكون false إذا لَدَينا أيّ أخطاء تحقّق من الصحة. فيمكننا فحص ذلك هنا. فلنقل، إذا ليس valid. أي إذا لم يكن field.state.meta.isValid

[03:35] فعندئذٍ يمتلك النموذج أخطاء ويلزمنا عرضها. فليُعرض في هنا بعض الأخطاء. وستكون أخطاؤنا في مصفوفة errors هذه، بالإضافة إلى errorMap هذا كذلك أيضًا. فبحسب الكيفية التي تريد بها

[03:47] عرض أخطائك، يمكنك أن تختار أحد هذه. ومن أجل الآن سأستخدم مصفوفة errors هذه فحسب. فببساطة سأضع div بنصّ أحمر هنا. وفي هنا سأتذكّر، تذكّر أنّ هذا مصفوفة. فيلزمنا

[04:02] عرض أخطائنا كلّها. وللآن سأحوّل ببساطة هذه المصفوفة إلى سلسلة نصّية (string) باستخدام join. فلنحصل على أخطائنا، أو عذرًا، على مصفوفة errors لدينا هكذا. ثم نستخدم join لإنشاء سلسلة نصّية من مصفوفتنا و

[04:18] نستخدم فاصلة (comma) فاصلًا. فالآن بهذا ينبغي أن نرى خطأنا معروضًا هنا.

[04:28] وسيحدث تحقّقنا كلّما كتبنا، وستظهر أخطاؤنا وتختفي بينما نكتب. وبالطبع يمكننا أيضًا تغيير هذا وجعله onBlur كذلك، كي — عذرًا — onBlur، كي لا يُجرى تحقّقنا إلا عند

[04:43] فقد الحقل تركيزه. فآه، عذرًا، ليس في listeners بل في validators هنا. فلنجرِّ تجديدًا (refresh) كذلك. الآن، بينما نكتب لا يحدث شيء. لكن إذا فقدنا الحقل التركيز وكان لَدَينا خطأ، فينبغي أن نحصل على خطأنا. أجل.

[05:01] حسنًا.

[05:02] للآن، سأُبقيه ربما على onChange. والآن، فلنفعل شيئًا.

[05:07] سأعلّق (comment) هذا فقط للآن كي نمتلك نموذجنا كاملًا هنا. ولنقل إنّه إذا امتلكنا أخطاءً في نموذجنا، إذا امتلكنا أيّ خطأ، فينبغي ربما أن نُعطّل زر الإرسال (submit) هذا.

[05:22] فكيف يمكننا فعل ذلك؟ يلزمنا الاشتراك (subscribe) في شيءٍ في حالة نموذجنا. فتذكّر أنّه يمكننا ذلك إمّا باستخدام store أو إجراؤه كذلك باستخدام مكوّن subscribe الذي استخدمناه فعلًا هنا كذلك أيضًا.

[05:36] سأستخدم subscribe لأنّنا نحتاج إلى تغيير شيءٍ في واجهة المستخدم (UI) لدينا بناءً على ما إذا كنا بمقدورنا إرسال نموذجنا أم لا.

[05:42] فليذهب في هنا إلى زر الإرسال لدينا وفي الأسفل من هنا. وسأقصّه ربما من هنا في الوقت الحالي.

[05:51] ثم نغلّفه ضمن مكوّن subscribe هذا. وفي هنا لنستخدم form.subscribe. وما يلزمنا الاشتراك فيه هو شيءٌ في حالة النموذج، وهو راية (flag) تُدعى canSubmit. فبصفتها عاملَ انتقاء (selector) هنا،

[06:06] سأمرّر دالة. وفي دالتنا، تذكّر أنّنا نتلقّى حالة نموذجنا فيمكننا الاشتراك في أشياء، عذرًا، الاشتراك في أشياء في حالة نموذجنا. ما يلزمنا الاشتراك فيه هو state.canSubmit.

[06:22] ستكون false إذا امتلكنا أيّ أخطاء تحقّق. والآن، داخل أبناء (children) المكوّن يمكننا تمرير دالة نتلقّى بها الحالة التي اشتركتنا فيها. فلنمرّر في هنا، هنا، دالة. سنحصل

[06:34] على الوصول إلى canSubmit.

[06:36] والآن من هذه الدالة يمكننا إعادة زرنا. فسألصق زري من جديد. لكن الآن فلدينا الوصول إلى canSubmit ويمكننا تعطيل زرنا إذا لم نكن بمقدورنا الإرسال. فإذا لم يكن canSubmit فسنُعطّل

[06:50] الزر. وكذلك لكي يصبح هذا ظاهرًا، إذا كان زرنا معطَّلًا فسأجعل الشفافية (opacity) ربما 40 أو ما يشابه.

[06:59] ولنضيف أيضًا إذا كنّا معطّلين أن نجعل المؤشِّر (cursor) من الصنف not-allowed. فلنضيف في هنا cursor وnot-allowed كذلك أيضًا.

[07:10] فالآن كما ترى زرنا معطّل، لكن إن لم نمتلك أيّ أخطاء، فسيعود زرنا مفعّلًا من جديد.

[07:18] ممتاز. فشيءٌ آخر يمكننا فعله، إذ لنتذكّر، فلنستحضر تعليِق الحالة (state) والميتاداتا (metadata) لحقلنا، حقل الاسم الأول هذا هنا. وقد شاهدنا هذه الخاصية errorMap التي لدينا هنا

[07:33] وهي التي ستتضمّن أخطاءنا إذا امتلكنا أخطاءً. غير أنّها، بخلاف خاصية errors التي ستكون مجرّد مصفوفة من الأخطاء، ستكون خريطةً (map) فيها معلومات إضافية عن كيفية حدوث هذا الخطأ

[07:45] سواءً باستخدام دالة onChange أم onBlur وما إلى ذلك. فلنجرب هذا سريعًا هنا عن طريق إضافة دالة onBlur هنا كذلك، لأنّه يمكننا إجراء التحقّق عبر دوالٍّ إضافية. يمكننا إجراء تحقّقاتٍ بينما نكتب، وكذلك

[07:58] يمكننا إجراء تحقّقاتٍ أخرى بينما نكتب، أو عند فقد حقلنا تركيزه. فليُضاف onBlur هنا كذلك. وسنحصل أيضًا على قيمتنا، فلنجري — عذرًا — فلنجري بعض التحقّق الآخر هنا. فلنفحص ربما ما إذا

[08:12] كانت قيمتنا ربما لا تساوي John.

[08:17] فلنعد خطأً آخر، فلنقل: your name must be John. والآن، وربما فلنجدّده كذلك. فالآن كلّما كتبنا فسيحدث خطأ onChange.

[08:36] غير أنّه عندما نفقد الحقل تركيزه فسيعمل الخطأ الآخر من onBlur، وسنحصل الآن على خطأين، وهما في هذه المصفوفة خطأ onChange وخطأ onBlur. غير أنّه، بالإضافة إلى ذلك، سنحصل في errorMap هذا على كِلَيهما كذلك. لكن هذه المرة نعلم أنّ هذا الخطأ حدث في

[08:49] onBlur بينما حدث هذا الآخر في onChange. وقد تحتاج ربما إلى استخدام هذه المعلومات في واجهتك الرسومية (UI) بشكلٍ ما. أما أنا فلن أستخدمها، وإنّما أردت فقط أن أشير إلى أنّه من الممكن — في هنا — امتلاك تحقّقاتٍ متعددة باستخدام دوالٍّ

[09:03] متعددة في خاصية validators هذه هنا.