البرمجة مبتدئ 9 دقيقة

كيفية التعامل مع إرسال النماذج والتحقق منها في JavaScript

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

يبني هذا الدليل معالج نماذج كامل: تحقق HTML5 للنتائج السريعة، ومعالج إرسال بـ JavaScript باستخدام FormData وfetch، وعرض أخطاء لكل حقل، ورحلة كاملة مع أخطاء التحقق 422 من السيرفر تُعاد توزيعها على الحقول المحددة.

بلا framework، وبلا مكتبة — المتصفح الأصلي فقط.

الخطوات

  1. 1

    ضع النموذج بقيود HTML5

    استخدم سمات HTML5 الأصلية للتحقق الأساسي قبل تشغيل JavaScript. required وtype="email" وminlength وpattern تمنع الإرسالات الواضحة الخطأ وهي متاحة افتراضياً. أضف عنصراً مجاوراً لكل حقل لعرض رسائل خطأ مخصصة.

    html
    <form id="register-form" novalidate>
      <div class="field">
        <label for="name">Name</label>
        <input id="name" name="name" type="text" required minlength="2">
        <span class="field-error" aria-live="polite"></span>
      </div>
    
      <div class="field">
        <label for="email">Email</label>
        <input id="email" name="email" type="email" required>
        <span class="field-error" aria-live="polite"></span>
      </div>
    
      <button type="submit">Register</button>
    </form>
  2. 2

    اعترض الإرسال بـ preventDefault

    أضف مستمع submit على عنصر <form> — لا على الزر. استدعِ event.preventDefault() فوراً لإيقاف تنقل المتصفح الافتراضي. هذا يمنحك تحكماً كاملاً فيما يحدث بعد ذلك.

    javascript
    const form = document.getElementById('register-form');
    
    form.addEventListener('submit', async (event) => {
      event.preventDefault();
      await handleSubmit(form);
    });
  3. 3

    تحقق من الحقول قبل الإرسال

    استخدم Constraint Validation API (input.validity) للتحقق من كل حقل. اكتب دالة مساعدة صغيرة تقرأ حالة التحقق وتُعيد رسالة مقروءة. امسح الأخطاء السابقة أولاً، ثم أعِد التحقق.

    javascript
    function getValidationMessage(input) {
      if (input.validity.valueMissing) return 'This field is required.';
      if (input.validity.typeMismatch) return `Please enter a valid ${input.type}.`;
      if (input.validity.tooShort) return `Minimum ${input.minLength} characters required.`;
      if (input.validity.patternMismatch) return input.title || 'Invalid format.';
      return '';
    }
    
    function validateForm(form) {
      let valid = true;
      form.querySelectorAll('input').forEach((input) => {
        const msg = getValidationMessage(input);
        showFieldError(input, msg);
        if (msg) valid = false;
      });
      return valid;
    }
  4. 4

    أظهر الأخطاء وامسحها لكل حقل

    لكل input عنصر .field-error مجاور. اكتب دالتين مساعدتين — واحدة لضبط الخطأ وأخرى لمسحه. أضف كلاس is-invalid للـ input لتتمكن من تنسيق الحدود الحمراء عبر CSS.

    javascript
    function showFieldError(input, message) {
      const errorEl = input.closest('.field')?.querySelector('.field-error');
      if (!errorEl) return;
    
      if (message) {
        errorEl.textContent = message;
        input.classList.add('is-invalid');
        input.setAttribute('aria-invalid', 'true');
      } else {
        errorEl.textContent = '';
        input.classList.remove('is-invalid');
        input.removeAttribute('aria-invalid');
      }
    }
    
    // Clear errors when the user starts fixing them
    form.querySelectorAll('input').forEach((input) => {
      input.addEventListener('input', () => showFieldError(input, ''));
    });
  5. 5

    اجمع البيانات وعطّل زر الإرسال

    new FormData(form) تقرأ كل <input> و<select> و<textarea> مسماة تلقائياً. عطّل زر الإرسال قبل الطلب لمنع الإرسال المزدوج، وأعِد تفعيله في كتلة finally.

    javascript
    async function handleSubmit(form) {
      if (!validateForm(form)) return;
    
      const btn = form.querySelector('[type="submit"]');
      btn.disabled = true;
      btn.textContent = 'Sending…';
    
      const formData = new FormData(form);
    
      try {
        const response = await fetch('/api/register', {
          method: 'POST',
          body: formData, // No Content-Type header: browser sets multipart boundary
        });
    
        if (response.status === 422) {
          const { errors } = await response.json();
          applyServerErrors(form, errors);
          return;
        }
    
        if (!response.ok) throw new Error(`Server error: ${response.status}`);
    
        form.reset();
        showSuccess('Registration complete!');
      } catch (err) {
        showError(err.message);
      } finally {
        btn.disabled = false;
        btn.textContent = 'Register';
      }
    }
  6. 6

    وزّع أخطاء التحقق 422 على الحقول

    تُعيد ردود السيرفر لأخطاء التحقق (HTTP 422) عادةً كائن JSON يُعيّن أسماء الحقول على مصفوفات أخطاء. كرّر على كائن الأخطاء واستدعِ showFieldError لكل حقل. هذا يُغلق حلقة التغذية الراجعة بنظافة بدون إعادة تحميل الصفحة.

    javascript
    // Server returns: { errors: { email: ['Already taken.'], name: ['Too short.'] } }
    function applyServerErrors(form, errors) {
      Object.entries(errors).forEach(([fieldName, messages]) => {
        const input = form.querySelector(`[name="${fieldName}"]`);
        if (input) {
          showFieldError(input, messages[0]); // Show first error per field
        }
      });
    }
  7. 7

    أرسل JSON بدلاً من FormData عند الحاجة

    إذا كان الـ API يتوقع جسم JSON (مثل REST API لا يقبل multipart)، حوّل FormData إلى كائن بسيط وحوّله إلى نص. اضبط رأس Content-Type صراحةً.

    javascript
    const payload = Object.fromEntries(new FormData(form));
    
    const response = await fetch('/api/register', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
    });

نصائح ومحاذير

  • أضف <code>novalidate</code> لعنصر النموذج لإلغاء فقاعات أخطاء المتصفح الأصلية والتحكم الكامل في تجربة المستخدم عبر JavaScript.
  • أعِد تفعيل زر الإرسال دائماً في <code>finally</code>، لا في فرع النجاح فقط — وإلا ستتركه الأخطاء معطلاً بشكل دائم.
  • أخبر قارئات الشاشة بأخطاء التحقق عبر <code>aria-live="polite"</code> على عناصر الأخطاء، و<code>aria-invalid="true"</code> على الحقل المخطئ.
  • لمربعات الاختيار والأزرار الدائرية، لا تُضمّن <code>FormData</code> إلا القيم المُحددة. إذا احتاج المربع غير المحدد إلى إرسال <code>false</code>، حوّل إلى كائن بسيط وتعامل معه صراحةً.
  • لا تثق أبداً بالتحقق من جانب العميل وحده — تحقق دائماً من جهة السيرفر. التحقق من العميل هو تجربة مستخدم، ليس أمناً.

خاتمة

معالج النماذج المتين ليس كثير الكود — نحو 60 سطراً تُغطي التحقق والإرسال وعرض الأخطاء والرحلة مع السيرفر. النمط هنا قابل لإعادة الاستخدام: بدّل الـ endpoint وأي مجموعة حقول. أتقنه مرة واحدة ولن تحتاج مكتبة نماذج في أغلب مشاريعك.

#JavaScript #Forms #Validation
العودة إلى جميع الأدلة

هل تحتاج مساعدة في مشروعك؟

احجز استشارة مجانية لمدة 30 دقيقة لمناقشة تحدياتك التقنية واستكشاف الحلول معًا.