اذهب إلى المحتوى

التحقق من صحة بيانات استمارة ويب في طرف العميل


ابراهيم الخضور

من الضروري التحقق من ملء بيانات جميع عناصر تحكم استمارة ويب وفق التنسيق الصحيح قبل إرسالها إلى الخادم، وتُدعى هذه العملية التحقق من الاستمارة في طرف العميل client-side form validation، وهي تساعد على ضمان توافق البيانات مع المتطلبات المخصصة لكل عنصر تحكم من عناصر الاستمارة قبل إرسالها للخادم. لهذا سيقودك هذا المقال عبر المفاهيم اﻷساسية التي تحتاجها للتحقق من البيانات في طرف العميل.

ننصحك قبل المتابعة في قراءة هذا المقال الاطلاع على أساسيات HTML وعلى أساسيات تنسيق الصفحات باستخدام CSS وكذلك أساسيات لغة جافا سكريبت.

إن التحقق من صحة البيانات التي يدخلها المستخدم أثناء كتابتها في المتصفح ميزة هامة، وتقدم للمستخدم تجربة أفضل، فهي تنبهه إلى اﻷخطاء التي ارتكبها كي يصححها مباشرة. فإرسال بيانات خاطئة إلى الخادم ستؤدي إلى رفضها إضافة إلى التأخير الذي يحدث نتيجة إرسال البيانات ومن ثم الانتظار حتى يتحقق منها الخادم ويعيدها طالبًا منك تصحيحها.

مع ذلك لا يمكن أن نعتمد كليًا على التحقق من طرف العميل فقط وذلك لأسباب أمنية، فمن السهل جدًا تجاوز التحقق من طرف العميل من قبل مستخدمين مشبوهين وإرسال بيانات غير صحيحة أو ضارة إلى الخادم. لهذا يجب التحقق من صحة البيانات في كلا الطرفين. وعلى الرغم من أننا لن نتحدث عن حاليًا عن التحقق من البيانات في طرف الخادم، لكن عليك تذكر ذلك جيدًا.

ما الذي نعنيه بالتحقق من الاستمارة؟

جرّب أن تزور أي موقع ويب مشهور يعرض استمارة تسجيل وستلاحظ أنه يقدم توصيات بتصحيح البيانات المدخلة إن لم تكتبها وفق الصيغة المطلوبة الذي تتوقعه الاستماره. فقد تتلقى رسائل مثل

  • "هذا الحقل مطلوب": أي لا يمكنك ترك هذا الحقل فارغًا.
  • "الرجاء إدخال رقم الهاتف وفق التنسيق xxx-xxxx": أي ينبغي إدخال البيانات بتنسيق معين حتى تُعد صالحة كرقم هاتف.
  • "الرجاء إدخال عنوان بريد إلكتروني صالح": أي لم تدخل البريد الإلكتروني وفق الصيغة المطلوبة.
  • "كلمة السر يجب أن تكون بين 8 إلى 30 محرفًا، وتضم على اﻷقل حرفًا كبيرًا ورمزًا ورقمًا": أي المطلوب إدخال بيانات وفق تنسيق مخصص ومحدد تمامًا.

يُدعى ذلك التحقق من الاستمارة form validation. فعندما تُدخل البيانات إلى الاستمارة يتحقق المتصفح (والخادم) من أن هذه البيانات وفق الصيغة الصالحة أو الحدود التي يفرضها التطبيق. وعندما يتحقق المتصفح من البيانات ندعوه التحقق من طرف العميل client-side validation، بينما ندعوه تحقق من طرف الخادم server-side validation عندما ينفذ الخادم عملية التحقق، وسنقتصر في مقالنا كما وضحنا سابقًا شرح آلية التحقق من طرف العميل.

إن كانت البيانات المدخلة إلى الاستمارة مطابقة للصيغة أو الحدود المطلوبة، ستُسلَّم الاستمارة إلى الخادم وقد تحفظ البيانات في قاعدة بيانات، بينما إن لم تكن البينات مطابقة لما هو مطلوب، فلن تّرسل إلى الخادم ويعرض المتصفح رسالة خطأ تشير إلى ما يجب عليك تصحيحه ويتيح لك المحاولة مجددًا.

وطالما أننا نريد من عملية ملء الاستمارة أن تكون سهلة إلى أبعد الحدود، قد تتساءل لماذا نربك أنفسنا بالتحقق من كل البيانات التي نُدخلها؟ إليك ثلاثة أسباب أساسية:

  • الحاجة إلى بيانات صحيحة وفق الصيغة الصحيحة. فلن يعمل التطبيق بالشكل المطلوب إن خُزّنت بيانات المستخدم بصيغة خاطئة أو كانت غير صالحة أو لم تكن موجودة أصلًا.
  • الحاجة إلى حماية بيانات المستخدم. فإجبار المستخدم على إدخال كلمة سر قوية وفق صيغة محددة تُسهِّل حماية بيانات حسابه.
  • الحاجة إلى حماية الموقع. فهناك طرق كثيرة يمكن فيها للمخترقين من إساءة استعمال الاستمارات غير المحمية لتخريب أمان مواقع الويب.

تحذير: لا تثق أبدًا بالبيانات التي يرسلها المستخدم إلى الخادم. وحتى لو تحققت الاستمارة من صحة البيانات المدخلة ومنعت المستخدم من إرسال بيانات غير واضحة، يمكن للمخترقين تغيير طلبات الشبكة التي تصل المتصفح بالخادم.

اﻷنواع المختلفة للتحقق في طرف العميل

هناك نوعان مختلفان للتحقق في طرف العميل ستواجههما في الويب:

  1. التحقق المدمج built-in validation: يستخدم وسيلة التحقق التي تقدمها بعض عناصر HTML، وقد رأينا العديد منها سابقًا مثل حقل إدخال البريد اﻹلكتروني. إذ لا يتطلب هذا النوع من التحقق الكثير من شيفرات جافا سكريبت، وله أداء أفضل من التحقق باستخدام جافا سكريبت لكن الأسلوب الثاني أكثر قابلية للتخصيص.
  2. التحقق باستخدام جافا سكريبت JavaScript validation: يستخدم شيفرة جافا سكريبت للتحقق من بيانات الاستمارة، وهو أسلوب قابل للتخصيص بالكامل، لكن عليك كتابة جميع تفاصيل العملية بنفسك (أو استخدام مكتبات جاهزة بالطبع).

استخدام التحقق المدمج من بيانات الاستمارة

من أبرز ميزات عناصر التحكم الحديثة في الاستمارات هي قدرتها على التحقق من صلاحية البيانات المدخلة إليها دون الاعتماد على جافا سكريبت. يتحقق العنصر من البيانات باستخدام خاصيات التحقق لعناصر تحكم النموذج، وقد رأينا سابقًا العديد منها، سنحاول مراجعتها تاليًا:

  • required: تحدد هذه الخاصية إذا ما كان على المستخدم ملء عنصر التحكم قبل إرسال البيانات أم لا.
  • minlength و maxlength: تحددان الطول اﻷدنى واﻷعلى للبيانات النصية المدخلة.
  • min و max: تحددان الحد اﻷدنى واﻷعلى لقيم مدخلات عددية.
  • type: تحدد نوع عنصر اﻹدخال سواء نص أو بريد إلكتروني أو قيمة عددية وهكذا.
  • pattern: تقبل تعبير نمطي regular expression يعرف نمط أو صيغة المدخلات التي يجب اتباعها عند إدخال البيانات إلى عنصر التحكم.

فإن خضعت البيانات المدخلة إلى عنصر تحكم لجميع القواعد التي تحددها تلك الخاصيات، ستُعد بيانات صالحة وإلا تًعد العكس. وعندما تكون قيمة أي مُدخل صحيحة، ستكون النقاط التالية محققة:

  • يمكن أن تستهدف العنصر عبر صنف التنسيق الزائف valid: لتطبيق تنسيق CSS محدد عليه.
  • إن حاول المستخدم إرسال البيانات، فسيعمل المتصفح على تسليمها إن لم يكن هناك أمر آخر يمنع ذلك (مثل شيفرة جافا سكريبت).

وعندما تكون البيانات المدخلة غير صالحة، فالنقاط التالية محققة:

  • يمكن أن تستهدف العنصر من خلال الصنف الزائف invalid: وأصناف أخرى أحيانًا مثل out-of-range: وفقًا للخطأ في البيانات المدخلة، مما يسمح بتطبيق تنسيق مخصص على العنصر.
  • سيمنع المتصفح المستخدم من تسليم الاستمارة إن حاول ذلك، ويعرض رسالة خطأ.

ملاحظة: هناك الكير من اﻷخطاء التي تمنع تسليم الاستمارة مثل badInput و patternMismatch و rangeOverflow أو rangeUnderflow و stepMismatch و tooLong أو tooShort و typeMismatch و valueMissing أو customError.

أمثلة عن استخدام التحقق المدمج من صحة بيانات عنصر التحكم

نناقش في هذا القسم استخدام بعض الخاصيات التي ذكرناها سابقًا.

ملف بسيط للبدء

لنبدأ أمثلتنا بمثال بسيط يضم عنصر إدخال تختار فيه الموز أو الكرز. يستخدم الملف عنصر إدخال نصي <input> مع عنوان مرافق <label> وزر إرسال <button>. بإمكانك إيجاد الشيفرة المصدرية للمثال على جيت-هاب:

<form>
 <label for="choose">Would you prefer a banana or cherry?</label>
 <input id="choose" name="i-like" />
 <button>Submit</button>
</form>

وإليك شيفرة تنسيق CSS:

input:invalid {
 border: 2px dashed red;
}

input:valid {
 border: 2px solid black;
}

وحتى تتابع معنا، انسخ ملف المثال على جهازك وضعه في مجلد جديد.

الخاصيات المطلوبة

تُعد الخاصية required من أبسط طرق التحقق في HTML. ولكي تجعل إدخال بيانات ضمن عنصر تحكمًا إجباريًا، أضف هذه الخاصية إلى العنصر، وعندها يمكنك استهداف العنصر باستخدام الصنف required:، ولن تُرسل الاستمارة وسيعيد المتصفح رسالة خطأ عندما تحاول تسليم الاستمارة وهذا العنصر فارغ. وسيعدُّ المتصفح العنصر غير صالح طالما أنه فارغ ويمكن استهدافه حينها بالصنف invalid::

<form>
 <label for="choose">Would you prefer a banana or cherry? (required)</label>
 <input id="choose" name="i-like" required />
 <button>Submit</button>
</form>

ستكون شيفرة التنسيق مضمّنه في ملف HTML:

input:invalid {
 border: 2px dashed red;
}

input:invalid:required {
 background-image: linear-gradient(to right, pink, lightgreen);
}

input:valid {
 border: 2px solid black;
}

يسبب التنسيق السابق ظهور حواف متقطعة باللون الأحمر عندما تكون القيمة المدخلة غير صالحة، وحواف متصلة باللون الأسود عندما تكون صحيحة. كما أضفنا خلفية لونية متدرجة عندما يكون عنصر اﻹدخال مطلوبًا وقيمته غير صالحة. جرّب المثال مباشرة في المحرر التفاعلي التالي:

 

جرب النقر على زر اﻹرسال عندما يكون المربع النصي فارغًا، سيكتسب عندها عنصر اﻹدخال تركيز الدخل وتظهر لك رسالة الخطأ التالية:
"Please fill out this field" ولن تُسلًم بيانات الاستمارة.

إن وجود الخاصية required ضمن أي عنصر يدعم هذه الخاصية، يعني إمكانية استهداف العنصر من قبل الصنف required: سواء كان العنصر فارغًا أو لا. بينما إن كان العنصر فارغًا، سيستهدفه أيضًا الصنف invalid:.

ملاحظة: لتقديم تجربة مستخدم جيدة، بيّن للمستخدم الحقول المطلوبة. هذا اﻷمر مطلوب أيضًا وفق توجيهات WCAG لسهولة الوصول. وانتبه دائمًا لعدم إجبار المستخدم على إدخال بيانات غير ضرورية، فلا معنى أن تجبره على إدخال جنسه أو لقبه.

تقييم صلاحية مدخلات باستخدام التعابير النمطية regex

من الخاصيات المفيدة أيضًا نجد pattern التي تتوقع تعبيرًا نمطيًا regex قيمةً لها. والتعبير النمطي هو سلسلة من الرموز التي تستخدم ﻹيجاد تشكيلة محددة من المحارف ضمن سلسلة نصية، فهو مثالي جدًا للتحقق من المدخلات المختلفة، وله استخدامات كثيرة في جافا سكريبت.

و التعابير النمطية هي بالفعل نماذج معقدة، ولا ننوي أن نشرحها في المقال، لكن إليك بعض اﻷمثلة البسيطة التي توضح مفهومها:

  • a: تعبير نمطي يطابق الحرف a (وليس b أو aa وهكذا).
  • abc: يطابق سلسلة من اﻷحرف تبدأ ب a يليه b يليه c.
  • ab?c: يطابق سلسلة من اﻷحرف تبدأ ب a وقد يليه b فقط ثم c (يطابق "ac" و "abc" وليس "aac").
  • ab*c: يطابق سلسلة من اﻷحرف تبدأ ب a وقد يليه عدة محارف b فقط ثم c (يطابق "ac" و "abc" و "abbbc").
  • a|b: يبحث عن أحد المحرفين a أو b.
  • abc|xyz: يطابق abc تمامًا أو xyz تمامًا.

بالطبع هناك الكثير والكثير من اﻷنماط التي لم نذكرها، وللاطلاع على هذه اﻷنماط بأكملها وطريقة استخدامها ننصح بمطالعة مقال مقدمة في التعابير النمطية Regular Expressions.

لنحاول تحديث المثال السابق من خلال إضافة الخاصية pattern واستخدام تعبير نمطي مناسب:

<form>
 <label for="choose">Would you prefer a banana or a cherry?</label>
 <input id="choose" name="i-like" required pattern="[Bb]anana|[Cc]herry" />
 <button>Submit</button>
</form>

إليك نتيجة العمل:

يقبل عنصر اﻹدخال في هذه النسخة من المثال أربع احتمالات هي: "banana" أو "Banana" أو "cherry" أو "Cherry". ولأن التعبير النمطي حساس لحالة اﻷحرف، فقد جعلناه يدعم الكلمة التي تبدأ بحرف كبير أو صغير، من خلال وضع الخيارين ضمن قوسين مربعين [Bb].

حاول تغيير التعبير النمطي ضمن الخاصية pattern ليماثل بعض القواعد التي أشرنا إليها سابقًا وراقب تأثيرها على القيمة التي تُدخلها ضمن عنصر اﻹدخال. إن لم تتطابق القيمة المدخلة مع تسلسل التعبير النمطي في الخاصية pattern يتطابق عندها عنصر اﻹدخال والصنف invalid:.

ملاحظة: لا تحتاج بعض عناصر اﻹدخال إلى الخاصية pattern حتى تُقيّم مُدخلاتها بالاعتماد على التعابير النمطية مثل البريد اﻹلكتروني email، إذ تُقيَّم المدخلات بالمقارنة مع نمط خاص بالبريد اﻹلكتروني، مع أو بدون فواصل في حال استُخدمت الخاصية multiple.

ملاحظة: لا يدعم العنصر <textarea> الخاصية pattern.

تحديد طول المدخلات

بإمكانك تحديد عدد المحارف في حقل إدخال نصي من خلال الخاصيتين minlength و maxlength. وسيكون المُدخل غير صالح إن كان عدد المحارف أدنى من minlength أو أكثر من maxlength.

لا تسمح المتصفحات للمستخدم عادة بكتابة عدد محارف أكثر من الحد الأعلى المسموح. ولتزيد من جودة تجربة المستخدم يمكنك -إضافة إلى استخدام الخاصية maxlength- إظهار عدّاد للمحارف المتبقية التي يمكن للمستخدم إدخالها، مثل تلك العدادات التي تظهر عندما تحاول كتابة منشور على وسائط التواصل الاجتماعي. وهنا يأتي دور جافا سكريبت مع الخاصية maxlength لتنفيذ اﻷمر.

تحديد مجالات القيم للمدخلات

تُستخدم الخاصيتان min و max لتحديد أعلى وأدنى قيمة يمكن إدخالها ضمن عنصر إدخال عددي مثل <"input type= "number>، وستكون القيمة خاطئة إن خرجت عن هذا المجال.

لنلق نظرة على مثال آخر، ولنبدأ بإنشاء نسخة جديدة عن ملف مثال الفواكه السابق، ثم حذف محتوى العنصر <body> واستبداله بالشيفرة التالية:

<form>
 <div>
    <label for="choose">Would you prefer a banana or a cherry?</label>
    <input
     type="text"
     id="choose"
     name="i-like"
     required
     minlength="6"
     maxlength="6" />
 </div>
 <div>
    <label for="number">How many would you like?</label>
    <input type="number" id="number" name="amount" value="1" min="1" max="10" />
 </div>
 <div>
    <button>Submit</button>
 </div>
</form>
  • حددنا عدد المحارف اﻷعلى واﻷدنى في حقل إدخال النصي ليكون 6 وهو نفس عدد الحروف في الكلمتين banana و cherry.
  • وحددنا قيمة عنصر اﻹدخال العددي ليكون الحد اﻷدنى min هو 1 والحد اﻷعلى max هو 10، وسيكون أي عدد خارج هذا المجال غير صالح ولن يتمكن المستخدم من استخدام زر الزيادة واﻹنقاص خارجه. وإن أدخل المستخدم عدد خارج هذا المجال يدويًا سيكون غير صالح أيضًا. وطالما أن هذا العنصر غير مطلوب، فإزالة هذه القيمة ستُبقي قيمة العنصر صالحة!

إليك نتيجة المثال:

ملاحظة: يأخذ العنصر <"input type="number> وغيره من العناصر مثل (range و date) الخاصية step التي تحدد مقدار الزيادة واﻹنقاص عند استخدام زر التحكم المخصص. لكن في مثالنا السابق لم نستخدم هذه الخاصية وستكون القيمة الافتراضية لها هي 1 وبالتالي لن تكون القيم ذات الفاصلة صالحة مثل 3.4.

المثال كاملًا

إليك المثال الكامل الذي يعرض استخدام ميزات التحقق المضمنة مع عناصر HTML:

  • شيفرة HTML:
<form>
 <fieldset>
    <legend>
     Do you have a driver's license?<span aria-label="required">*</span>
    </legend>
    <!-- While only one radio button in a same-named group can be selected at a time,
       and therefore only one radio button in a same-named group having the "required"
       attribute suffices in making a selection a requirement -->
    <input type="radio" required name="driver" id="r1" value="yes" /><label
     for="r1"
     >Yes</label
    >
    <input type="radio" required name="driver" id="r2" value="no" /><label
     for="r2"
     >No</label
    >
 </fieldset>
 <p>
    <label for="n1">How old are you?</label>
    <!-- The pattern attribute can act as a fallback for browsers which
       don't implement the number input type but support the pattern attribute.
       Please note that browsers that support the pattern attribute will make it
       fail silently when used with a number field.
       Its usage here acts only as a fallback -->
    <input
     type="number"
     min="12"
     max="120"
     step="1"
     id="n1"
     name="age"
     pattern="\d+" />
 </p>
 <p>
    <label for="t1"
     >What's your favorite fruit?<span aria-label="required">*</span></label
    >
    <input
     type="text"
     id="t1"
     name="fruit"
     list="l1"
     required
     pattern="[Bb]anana|[Cc]herry|[Aa]pple|[Ss]trawberry|[Ll]emon|[Oo]range" />
    <datalist id="l1">
     <option>Banana</option>
     <option>Cherry</option>
     <option>Apple</option>
     <option>Strawberry</option>
     <option>Lemon</option>
     <option>Orange</option>
    </datalist>
 </p>
 <p>
    <label for="t2">What's your email address?</label>
    <input type="email" id="t2" name="email" />
 </p>
 <p>
    <label for="t3">Leave a short message</label>
    <textarea id="t3" name="msg" maxlength="140" rows="5"></textarea>
 </p>
 <p>
    <button>Submit</button>
 </p>
</form>
  • شيفرة CSS:
form {
 font: 1em sans-serif;
 max-width: 320px;
}

p > label {
 display: block;
}

input[type="text"],
input[type="email"],
input[type="number"],
textarea,
fieldset {
 width: 100%;
 border: 1px solid #333;
 box-sizing: border-box;
}

input:invalid {
 box-shadow: 0 0 5px 1px red;
}

input:focus:invalid {
 box-shadow: none;
}
  • نتيجة عرض الشيفرة السابقة:

التحقق من الاستمارة باستخدام جافا سكريبت

لا بد من استخدام جافا سكريبت إن أردت التحكم الكامل بمظهر وشكل رسائل الخطأ، وهذا ما نناقشه في هذا القسم من المقال.

الواجهة البرمجية لتحديد صلاحية المُدخلات

تتكون هذه الواجهة البرمجية من مجموعة من التوابع والخاصيات تقدمها واجهات عناصر DOM التالية:

  • HTMLButtonElement: يمثل العنصر <button>
  • HTMLFieldSetElement: يمثل العنصر <fieldset>
  • HTMLInputElement: يمثل العنصر <Input>.
  • HTMLOutputElement: يمثل العنصر <output>.
  • HTMLSelectElement: يمثل العنصر <select>.
  • HTMLTextAreaElement: يمثل العنصر <textarea>.

وتضم الواجهة البرمجية الخاصيات التالية:

  • validationMessage: تعيد رسالة مخصصة تشرح حدود صلاحية قيمة عنصر التحكم في حال لم تكن صالحة. لكن إن لم يكن العنصر قابلًا لتحديد الصلاحية (أي قيمة الخاصية willValidate هي false) أو كانت قيمة العنصر صالحة، ستعيد الخاصية قيمة نية فارغة.
  • validity: تعيد كائن validityState يضم عدة خاصيات تصف حالة صلاحية العنصر. إليك أبرز هذه الخاصيات:
  • patternMismatch: تعيد القيمة true إن لم تطابق القيمة النمط الذي تحدده قيمة الخاصية pattern، و false إن لم يوجد تطابق. وفي حال أعادت القيمة true يمكن استهداف العنصر عبر الصنف invalid:.
  • tooLong: تعيد الخاصية القيمة true إن كانت القيمة المدخلة أطول من القيمة التي تحددها الخاصية maxlength و false إن كانت أقصر منها أو تساويها. وفي حال أعادت القيمة true يمكن استهداف العنصر عبر الصنف invalid:.
  • tooShort: تعيد الخاصية القيمة true إن كانت القيمة المدخلة أقصر من القيمة التي تحددها الخاصية minlength و false إن كانت أقصر منها أو تساويها. وفي حال أعادت القيمة true يمكن استهداف العنصر عبر الصنف invalid:.
  • rangeOverFlow: تعيد الخاصية القيمة true إن كانت القيمة المدخلة أكبر من القيمة التي تحددها الخاصية max و false إن كانت أقل منها أو تساويها. وفي حال أعادت القيمة true يمكن استهداف العنصر عبر الصنف invalid: و out-of-range:.
  • rangeUnderFlow: تعيد الخاصية القيمة true إن كانت القيمة المدخلة أكبر من القيمة التي تحددها الخاصية min و false إن كانت أكبر منها أو تساويها. وفي حال أعادت القيمة true يمكن استهداف العنصر عبر الصنف invalid:.
  • typeMismatch: تعيد الخاصية القيمة true إن لم تحقق قيمة الخاصية الصياغة المطلوبة (عندما يكون نوع عنصر اﻹدخال email أو url) و false إن كانت الصياغة صحيحة. وفي حال أعادت القيمة true يمكن استهداف العنصر عبر الصنف invalid:.
  • valid: تعيد الخاصية القيمة true إن لم تحقق قيمة الخاصية جميع حدود الصلاحية المتعلقة بها، وتُعد حينها صالحة، و false إن لم تحقق أحد القيود المفروضة عليها. وفي حال أعادت القيمة true يمكن استهداف العنصر عبر الصنف valid: وإلا يمكن استهدافها بالصنف invalid:.
  • valueMissing: تعيد الخاصية القيمة true إن ظهرت الخاصية required في العنصر وكان فارغًا وإلا أعادت false. وفي حال أعادت القيمة true يمكن استهداف العنصر عبر الصنف invalid:.
  • willValidate: تعيد الخاصية القيمة true في حال وجب التحقق من صلاحية القيمة المُدخلة عند إرسال الاستمارة، وإلا أعادت القيمة false.

كما تزودنا الواجهة البرمجية بتوابع تُطبق على العناصر السابقة وعلى عناصر الاستمارة:

  • ()checkValidity: يعيد القيمة true إن لم تكن هناك أية مشاكل في التحقق من صلاحية قيمة، وإلا تعيد false. وإن كانت القيمة غير صالحة، سيقع الحدث invaild على العنصر.

  • reportValidity(): يبلغ عن الحقول غير الصالحة باستخدام اﻷحداث. ولهذا التابع أهميته عندما يجتمع مع التابع ()preventDefault ضمن معالج الحدث onSubmit.

  • (setCustomValidity(message: يضيف رسالة خطأ مخصصة إلى العنصر. وعندما تخصص رسالة خطأ، سيُعد العنصر غير صالح، وستُعرض رسالة الخطأ. يسمح هذا التابع باستخدام جافا سكريبت لتهيئة حالة إخفاق عملية التحقق بشكل مختلف عن الطريقة المعيارية التي تتبعها HTML في تقييم القيمة. تُعرض هذه الرسالة للمستخدم عند اﻹبلاغ عن المشكلة.

    تنفيذ رسالة خطأ مخصصة

    يعرض المتصفح رسالة خطأ في كل مرة يحاول فيها المستخدم إرسال قيمة غير صالحة وفقًا لمعايير تحقق HTML، وتختلف طريقة عرض هذه الرسالة على المتصفح. ولهذا اﻵلية سلبيتان أساسيتان:

  • لا توجد طريقة معيارية متبعة لتغيير شكل وطبيعة الرسالة باستخدام CSS.

  • تعتمد على اﻹعدادات المحلية للمتصفح، فقد تكون لغة الصفحة مختلفة عن اللغة الافتراضية للمتصفح كما في لقطة الشاشة التالية:

01 error firefox win7

وتخصيص هذا النوع من الرسائل هو الاستخدام اﻷكثر شيوعًا للواجهة البرمجية الخاصة بالتحقق من صلاحية المدخلات، لهذا سنعمل على مثال يصف آلية عملها.

سنبدأ بملف HTML بسيط نضع ضمنه الشيفرة التالية:

<form>
 <label for="mail">
    I would like you to provide me with an email address:
 </label>
 <input type="email" id="mail" name="mail" />
 <button>Submit</button>
</form>

أضف شيفرة جافا سكريبت التالية إلى الصفحة ضمن العنصر <script>

const email = document.getElementById("mail");

email.addEventListener("input", (event) => {
 if (email.validity.typeMismatch) {
    email.setCustomValidity("I am expecting an email address!");
 } else {
    email.setCustomValidity("");
 }
});

تخزن شيفرة جافا سكريبت السابقة مرجعًا إلى عنصر إدخال بريد إلكتروني، ثم تضيف مترصد أحداث ينفذ بعض الشيفرة في كل مرة تتغير فيها القيمة المدخلة في العنصر.

تتحقق الشيفرة ضمن معالج الحدث إن أعادت الخاصية validity.typeMismatch لعنصر اﻹدخال القيمة true والتي تعني أن القيمة المدخلة غير صالحة، ولا تتطابق مع النمط المخصص لعنوان البريد اﻹلكتروني. عندها، نستدعي التابع ()setCustomValidity ليعرض رسالة الخطأ المخصصة. يُصيّر هذا التابع عنصر اﻹدخال بحيث تُعرض رسالة الخطأ المخصصة، ويُخفق تسليم الاستمارة.

بينما إن أعادت الخاصية القيمة false، نستدعي حينها التابع ()setCustomValidity لكن مع رسالة فارغة، ويصيَّر عنصر اﻹدخال لينجح تسليم أو إرسال الاستمارة.

مثال أكثر تفصيلًا

لنحاول اﻵن الاستفادة من الواجهة البرمجية لإنجاز مثال أكثر تعقيدًا للتحقق من صلاحية المدخلات.

إليك شيفرة HTML:

<form novalidate>
 <p>
    <label for="mail">
     <span>Please enter an email address:</span>
     <input type="email" id="mail" name="mail" required minlength="8" />
     <span class="error" aria-live="polite"></span>
    </label>
 </p>
 <button>Submit</button>
</form>

تستخدم الاستمارة البسيطة السابقة الخاصية novalidate ﻹلغاء التقييم التلقائي الذي ينفذه المتصفح. وهذا ما يسمح لشيفرتنا تولي مسؤولية التحقق. لن يمنع هذا اﻹلغاء بالطبع تقييم صلاحية المدخلات باستخدام الواجهة البرمجية ولا يمنع أيضًا استهداف العناصر عبر اﻷصناف الزائفة المناسبة. ويعني ذلك بكل بساطة أن المتصفح سيتنحى جانبًا ويكون عليك التحقق من صحة المدخلات وتنسيق الاستمارة بنفسك قبل تسليمها.

إن عنصر اﻹدخال الذي نتحقق من صلاحية مدخلاته هو عنصر إدخال بريد إلكتروني email وقد استخدمت ضمنه الخاصية required حتى يكون مطلوبًا وقررنا أن يكون أدنى عدد مقبول من المحارف هو 8 من خلال الخاصية minlength. وهكذا سنتحقق من تحقيق المدخلات القيود السابقة من خلال شيفرتنا ونعرض رسالة خطأ في حال وجوده.

ننوي عرض رسالة الخطأ ضمن عنصر <span>، واستخدمنا ضمنه الخاصية aria-live كي نتأكد من عرض رسالة الخطأ للجميع بمن فيهم مستخدمي قارئات الشاشة.

ملاحظة: إن الفكرة المفتاحية هنا هو أن الخاصية novalidate في الاستمارة هي من تمنع عرض رسالة الخطأ الافتراضية وتسمح لنا بعرض الرسالة المخصصة ضمن شجرة DOM بالطريقة التي نشاء.

إليك اآن بعض قواعد التنسيق البسيطة لتحسين مظهر الاستمارة وإظهار إشارات مناسبة عندما تكون البيانات المدخلة غير صالحة:

body {
 font: 1em sans-serif;
 width: 200px;
 padding: 0;
 margin: 0 auto;
}

p * {
 display: block;
}

input[type="email"] {
 appearance: none;

 width: 100%;
 border: 1px solid #333;
 margin: 0;

 font-family: inherit;
 font-size: 90%;

 box-sizing: border-box;
}

/* This is our style for the invalid fields */
input:invalid {
 border-color: #900;
 background-color: #fdd;
}

input:focus:invalid {
 outline: none;
}

/* This is the style of our error messages */
.error {
 width: 100%;
 padding: 0;

 font-size: 80%;
 color: white;
 background-color: #900;
 border-radius: 0 0 5px 5px;

 box-sizing: border-box;
}

.error.active {
 padding: 0.3em;
}

إليك شيفرة جافا سكريبت:

const form = document.querySelector("form");
const email = document.getElementById("mail");
const emailError = document.querySelector("#mail + span.error");

email.addEventListener("input", (event) => {
 // نتحقق في كل مرة نكتب فيها شيئًا من صلاحية القيمة المدخلة
 d.

 if (email.validity.valid) {
    // إن كانت هناك رسائل خطأ والقيم المدخلة صحيحة
    // أزل رسالة الخطأ
    emailError.textContent = ""; // Reset the content of the message
    emailError.className = "error"; // Reset the visual state of the message
 } else {
    // أظهر الخطأ في حال وجوده
    showError();
 }
});

form.addEventListener("submit", (event) => {
 // نسمح بإرسال الاستمارة إذا كانت القيمة المدخلة صالحة
 if (!email.validity.valid) {
    // اعرض رسالة الخطأ التالية
    showError();
    // نمنع إرسال الاستمارة بإلغاء الحدث
    event.preventDefault();
 }
});

function showError() {
 if (email.validity.valueMissing) {
    // إن كان الحقل فارغًا
    // اعرض رسالة الخطأ التالية
    emailError.textContent = "You need to enter an email address.";
 } else if (email.validity.typeMismatch) {
    // إن لم يضم الحقل عنوان بريد إلكتروني
    // اعرض رسالة الخطأ التالية
    emailError.textContent = "Entered value needs to be an email address.";
 } else if (email.validity.tooShort) {
    // If the data is too short,
    // اعرض رسالة الخطأ التالية
    emailError.textContent = `Email should be at least ${email.minLength} characters; you entered ${email.value.length}.`;
 }

 // اضبط التنسيق بالشكل المناسب
 emailError.className = "error active";
}

تشرح التعليقات المضمنة في الشيفرة ما نفعله جيدًا، لكن إن أردنا اﻹيجاز:

  • في كل مرة نغير فيها القيمة المدخلة نتحقق إن كانت البيانات صالحة، فإن كانت كذلك، نزيل أية رسالة خطأ تُعرض، وننفذ الدالة ()showErrorخلاف ذلك، لعرض رسالة الخطأ المناسبة.
  • نتحقق مجددًا من صلاحية البيانات في كل مرة نحاول فيها تسليم النموذج، ونسمح بإرسال النموذج فقط في حال كانت القيم صالحة وإلا ننفذ الدالة ()showError لعرض رسالة الخطأ المناسبة، ونمنع إرسال الاستمارة باستخدام التابع ()preventDefault.
  • تستخدم الدالة ()showError خاصيات مختلفة للكائن valid لتحديد ماهية الخطأ ومن ثم عرض رسالة الخطأ المناسبة.

إليك نتيجة الشيفرة السابقة:

وهكذا نرى أن واجهة التحقق من صلاحية المدخلات هي أداة فعالة جدًا للتعامل مع مسائل تقييم المدخلات، وتسمح لك بمجال تحكم أوسع بكثير عما يمكن أن تقدمه HTML و CSS.

تقييم النماذج دون استخدام الواجهة البرمجية المضمّنة

لن تتمكن من استخدام الواجهة البرمجية المضمنّة في بعض الحالات مثل حالة عناصر التحكم المخصصة، لكن باﻹمكان استخدام شيفرة جافا سكريبت للتحقق من بيانات الاستمارة، وعليك في هذه الحالة كتابة الشيفرة المناسبة بنفسك. وقبل أن تبدأ عليك طرح اﻷسئلة التالية على نفسك:

  • ما نوع التحقق الذي عليّ تنفيذه؟ عليك أن تحدد كيف تتحقق من صحة البيانات. هل ستستخدم العمليات على السلاسل النصية أو التحول بين اﻷنواع أو التعابير النمطية أو مزيج من كل ذلك، فاﻷمر يعود إليك.
  • ما الذي علي فعله إن لم تنجح عملية التحقق؟ هذه المسألة متعلقة تمامًا بواجهة المستخدم. إذ عليك أن تقرر سلوك الاستمارة: هل ترسل البيانات؟ هل يجب تظليل الحقول غير الصالحة؟ هل سأعرض رسالة خطأ؟
  • كيف أساعد المستخدم على تصويب البيانات غير الصالحة؟ من المهم جدًا تقديم معلومات تساعد المستخدم على ملء الاستمارة قدر اﻹمكان حتى لا يُصاب باﻹحباط. فعليك مثلًا تقديم اقتراحات مسبقة حتى يتوقع المستخدم ما سيفعله إضافة إلى تزويده برسائل خطأ واضحة.

مثال دون استخدام واجهة التحقق البرمجية

إليك نسخة مبسطة من المثال السابق لتوضيح فكرة التحقق من صلاحية المدخلات دون استخدام الواجهة البرمجية المضمّنة.

تبقى شيفرة HTML نفسها، لكننا أزلنا فقط الخاصية novalidate:

<form>
 <p>
    <label for="mail">
     <span>Please enter an email address:</span>
     <input type="text" id="mail" name="mail" />
     <span class="error" aria-live="polite"></span>
    </label>
 </p>
 <button>Submit</button>
</form>

لم تتغير شيفرة CSS كثيرًا، لكننا حولنا الصنف الزائف invalid: إلى صنف حقيقي لتفادي استخدام محددات الخاصيات attribute selector:

body {
 font: 1em sans-serif;
 width: 200px;
 padding: 0;
 margin: 0 auto;
}

form {
 max-width: 200px;
}

p * {
 display: block;
}

input#mail {
 appearance: none;
 width: 100%;
 border: 1px solid #333;
 margin: 0;

 font-family: inherit;
 font-size: 90%;

 box-sizing: border-box;
}

/* This is our style for the invalid fields */
input.invalid {
 border-color: #900;
 background-color: #fdd;
}

input:focus:invalid {
 outline: none;
}

/* This is the style of our error messages */
.error {
 width: 100%;
 padding: 0;

 font-size: 80%;
 color: white;
 background-color: #900;
 border-radius: 0 0 5px 5px;
 box-sizing: border-box;
}

.error.active {
 padding: 0.3em;
}

أما التغيير الجذري فهو في شيفرة جافا سكريبت، إذ ستحمل العبء اﻷكبر:

const form = document.querySelector("form");
const email = document.getElementById("mail");
const error = email.nextElementSibling;

// HTML وفق مواصفات
const emailRegExp =
 /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/;

// يمكن اﻵن بناء حدود للتقييم
// لأننا لم نعد نعتمد على اﻷصناف الزائفة
window.addEventListener("load", () => {
 // نتحقق أن عنصر اﻹدخال فارغ (تذكر العنصر غير مطلوب)
 // إن لم يكن كذلك نتحقق أن المحتوى هو عنوان بريد إلكتروني صالح
 const isValid = email.value.length === 0 || emailRegExp.test(email.value);
 email.className = isValid ? "valid" : "invalid";
});

// تعرف الشيفرة التالية ما يحدث عندما تتغير القيمة المدخلة
email.addEventListener("input", () => {
 const isValid = email.value.length === 0 || emailRegExp.test(email.value);
 if (isValid) {
    email.className = "valid";
    error.textContent = "";
    error.className = "error";
 } else {
    email.className = "invalid";
 }
});

// تعرف الشيفرة التالية ما يحدث عندما يحاول المستخدم إرسال الاستمارة
form.addEventListener("submit", (event) => {
 event.preventDefault();

 const isValid = email.value.length === 0 || emailRegExp.test(email.value);
 if (!isValid) {
    email.className = "invalid";
    error.textContent = "I expect an email, darling!";
    error.className = "error active";
 } else {
    email.className = "valid";
    error.textContent = "";
    error.className = "error";
 }
});

إليك النتيجة:

وكما نرى، اﻷمر ليس صعبًا للغاية، وتكمن الصعوبة في جعل الحل عامًا بما يكفي لتستخدمه عبر المنصات المختلفة وعلى أي استمارة قد تحاول إنشاءها. وتجدر اﻹشارة إلى وجود العديد من المكتبات الجاهزة لتنفيذ عمليات التحقق من المدخلات مثل Validate.js.

الخلاصة

تحتاج عملية التحقق في طرف العميل أحيانًا إلى شيفرة جافا سكريبت إن أردت تخصيص التنسيق ورسائل الخطأ، لكن من المهم جدًا التفكير بحرص شديد عندما يتعلق اﻷمر بالمستخدم. وتذكر أن تساعده في تصويب البيانات التي يُدخلها واحرص على أن:

  • تعرض رسائل خطأ صريحة.
  • تقدم صيغة بسيطة إدخال القيم وأن تتساهل في ذلك.
  • تشير إلى موقع الخطأ تمامًا وخاصة عندما يتكون الاستمارة كبيرة.

وعندما تتأكد من صلاحية جميع القيم في الاستمارة يمكنك حينها تسليمها إلى الخادم.

ترجمة -وبتصرف- للمقال: Client-side form validation

اقرأ أيضًا


تفاعل الأعضاء

أفضل التعليقات

لا توجد أية تعليقات بعد



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...