النماذج والتحقق من المدخلات
نتحقق من بيانات الزائر قبل إرسالها، ونعطيه رسائل واضحة. ⏱ نحو 30 دقيقة.
- تستمع لحدث
submitوتوقف الإرسال الافتراضي. - تقرأ القيم بـ
valueوتنظفها بـtrimوتحولها بـNumber. - تكتب قواعد تحقق وتعرض رسالة لكل خطأ.
- تشرح لماذا يلزم التحقق في الخادم أيضًا.
١حدث الإرسال submit
في الدرس 12 جعلنا المتصفح يتحقق بـ required. الآن نتحقق بأنفسنا بـ JavaScript لنعطي رسائل أوضح. نستمع لحدث submit على النموذج، ونوقف الإرسال إذا كانت البيانات خطأ:
<form id="f"> <label for="name">الاسم</label> <input id="name"> <button>إرسال</button> <p id="msg"></p></form><script src="script.js"></script>
label { display: block; margin-top: 8px; }input { padding: 6px; font: inherit; }.error { color: #C62828; font-size: 14px; }.ok { color: #2E8B3A; font-weight: bold; }
const form = document.querySelector("#f");const nameInput = document.querySelector("#name");const msg = document.querySelector("#msg"); form.addEventListener("submit", function (event) { event.preventDefault(); const name = nameInput.value.trim(); if (name === "") { msg.textContent = "اكتب اسمك من فضلك"; msg.className = "error"; } else { msg.textContent = `شكرًا يا ${name}، وصل طلبك`; msg.className = "ok"; }});
| السطر | معناه |
|---|---|
event.preventDefault() | أوقف السلوك الافتراضي (إرسال النموذج وتحميل صفحة جديدة)، لأننا سنتصرف بأنفسنا. |
.value | ما كتبه الزائر في الحقل، وهو نص دائمًا. |
.trim() | يحذف المسافات من البداية والنهاية، فلا يمر اسم كله مسافات. |
٢قواعد تحقق شائعة
| ما نتحقق منه | الكود |
|---|---|
| الحقل غير فارغ | value.trim() === "" |
| طول أدنى | value.length < 8 |
| يحتوي حرفًا معيّنًا | value.includes("@") |
| يبدأ بنص | phone.startsWith("05") |
| عدد في مجال | const age = Number(value); ثم age >= 16 && age <= 60 |
| ليس عددًا | isNaN(Number(value)) |
| حقلان متطابقان | pass.value === confirm.value |
٣تحقق كامل مع رسائل لكل حقل
<form id="f"> <label for="email">البريد</label> <input id="email"> <div class="error" id="emailErr"></div> <label for="pass">كلمة المرور</label> <input id="pass" type="password"> <div class="error" id="passErr"></div> <button>تسجيل</button> <p id="result"></p></form><script src="script.js"></script>
label { display: block; margin-top: 8px; }input { padding: 6px; font: inherit; }.error { color: #C62828; font-size: 14px; }.ok { color: #2E8B3A; font-weight: bold; }input.bad { border: 2px solid #C62828; }
document.querySelector("#f").addEventListener("submit", function (e) { e.preventDefault(); const email = document.querySelector("#email"); const pass = document.querySelector("#pass"); let valid = true; // نمسح الرسائل القديمة أولًا document.querySelector("#emailErr").textContent = ""; document.querySelector("#passErr").textContent = ""; email.classList.remove("bad"); pass.classList.remove("bad"); if (!email.value.includes("@")) { document.querySelector("#emailErr").textContent = "البريد يجب أن يحتوي @"; email.classList.add("bad"); valid = false; } if (pass.value.length < 8) { document.querySelector("#passErr").textContent = "كلمة المرور 8 أحرف على الأقل"; pass.classList.add("bad"); valid = false; } document.querySelector("#result").textContent = valid ? "✓ تم التسجيل" : "";});
الفكرة: متغيّر valid يبدأ صحيحًا، وأي خطأ يجعله خطأ. ونمسح الرسائل القديمة في البداية حتى لا تبقى بعد التصحيح.
٤حاسبة بالنموذج
النموذج لا يعني دائمًا «إرسالًا». هنا نقرأ الأرقام، ونحوّلها بـ Number، ونعرض النتيجة:
<form id="calc"> <label>السعر <input id="price" value="100"></label> <label>الخصم ٪ <input id="disc" value="20"></label> <button>احسب</button></form><p id="res"></p><script src="script.js"></script>
label { display: block; margin-top: 8px; }input { padding: 6px; font: inherit; }.error { color: #C62828; font-size: 14px; }.ok { color: #2E8B3A; font-weight: bold; }
document.querySelector("#calc").addEventListener("submit", function (e) { e.preventDefault(); const price = Number(document.querySelector("#price").value); const disc = Number(document.querySelector("#disc").value); const res = document.querySelector("#res"); if (isNaN(price) || isNaN(disc)) { res.textContent = "اكتب أرقامًا فقط"; return; } res.textContent = `بعد الخصم: ${price - price * disc / 100} ريال`;});
٥لماذا لا يكفي تحقق الواجهة؟
كل ما في المتصفح يمكن للزائر الماهر تعديله أو تجاوزه بأدوات المطوّر. لذلك:
- تحقق الواجهة لراحة الزائر: رسالة فورية واضحة.
- تحقق الخادم للأمان: يتكرر التحقق نفسه في الواجهة الخلفية قبل الحفظ.
- القاعدة الذهبية: لا تثق أبدًا بما يأتي من المتصفح.
توقّع وتحقّق
ما وظيفة event.preventDefault() في حدث submit؟
نوع قيمة input.value دائمًا:
Number.حذف المسافات من طرفي النص:
trim في JavaScript.أين يجب التحقق للأمان؟
الخلاصة
form.addEventListener("submit", …) ثمevent.preventDefault().valueنص دائمًا:trimللمسافات، وNumberللأرقام، وisNaNللتأكد.- متغيّر
validيبدأ صحيحًا، وأي خطأ يجعلهfalseويعرض رسالة. - تحقق الواجهة للراحة، وتحقق الخادم للأمان.
تحدٍّ برمجي: نموذج حجز طاولة
متقدماكتب التحقق من نموذج حجز طاولة في المقهى. عند الإرسال: اعرض رسالة الخطأ المناسبة في #msg بالصنف error، أو رسالة النجاح بالصنف ok.
- الاسم فارغ (أو مسافات): «اكتب اسمك»
- الجوال لا يبدأ بـ 05 أو ليس 10 أرقام: «رقم الجوال غير صحيح»
- عدد الأشخاص ليس من 1 إلى 10: «العدد من 1 إلى 10»
- كل شيء صحيح: «تم الحجز لـ (الاسم)» مثل: تم الحجز لـ سارة
- الصفحة لا تُعاد تحميلها عند الإرسال.
👀 اعرض شكل الناتج المطلوب
- الاسم الفارغ: «اكتب اسمك» بالصنف error.
- جوال خطأ: «رقم الجوال غير صحيح».
- عدد خطأ: «العدد من 1 إلى 10».
- كل شيء صحيح: «تم الحجز لـ سارة» بالصنف ok.
- الإرسال الافتراضي متوقف
(preventDefault).
💡 تلميح 1
phone.startsWith("05") و phone.length === 10💡 تلميح 2
people < 1 || people > 10حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.
<form id="book"> <label for="name">الاسم</label> <input id="name"> <label for="phone">الجوال</label> <input id="phone"> <label for="people">عدد الأشخاص</label> <input id="people" type="number"> <button>احجز</button></form><p id="msg"></p><script src="script.js"></script>
label { display: block; margin-top: 8px; }input { padding: 6px; font: inherit; }.error { color: #C62828; font-size: 14px; }.ok { color: #2E8B3A; font-weight: bold; }
const form = document.querySelector("#book");const msg = document.querySelector("#msg"); function show(text, cls) { msg.textContent = text; msg.className = cls;} form.addEventListener("submit", function (e) { e.preventDefault(); const name = document.querySelector("#name").value.trim(); const phone = document.querySelector("#phone").value.trim(); const people = Number(document.querySelector("#people").value); if (name === "") { show("اكتب اسمك", "error"); } else if (!phone.startsWith("05") || phone.length !== 10 || isNaN(Number(phone))) { show("رقم الجوال غير صحيح", "error"); } else if (people < 1 || people > 10) { show("العدد من 1 إلى 10", "error"); } else { show(`تم الحجز لـ ${name}`, "ok"); }});