فصل پیوست ۳: ثبت فرم و اعتبارسنجی‌های ناهمگام

Registration of Forms and Asynchronous Validations

Vue.JS 2 - فصل پیوست 3: ثبت فرم و اعتبارسنجی های ناهمگام - قسمت 134

در جلسات قبل به طور کامل با انواع اعتبارسنجی های مهم آشنا شدیم. البته لازم به ذکر است که زمان کافی برای بررسی تک تک موارد را نداشتیم و شما می توانید اطلاعات بیشتری را در صفحه رسمی Vuelidate پیدا کنید، گرچه که مباحث زیادی باقی نمانده است. یکی از کار هایی که دوست دارم با برنامه مان انجام بدهیم، غیرفعال کردن دکمه submit در صورت داشتن خطا در فرم است. برای این کار روش های مختلفی وجود دارد. به طور مثال می توانیم Disabled را با v-bind به دکمه submit متصل کنیم اما چطور باید این کار را انجام بدهیم؟ آیا باید هر فیلد را جداگانه به disabled پاس بدهیم. مثلا:

<button type="submit" :disabled="$v.email.$error || $v.age.$error || ...">Submit</button>

قطعا این کار بسیار سختی است و فقط برای فرم های بسیار کوچک جواب می دهد. اگر یادتان باشد ما به خصوصیت error$ روی شیء اصلی v$ (شیء vuelidate) نیز دسترسی داریم بنابراین می توان گفت:

<button type="submit" :disabled="$v.$error">Submit</button>

اما این روش نیز جالب نیست چرا که دکمه submit باید از همان ابتدا غیر فعال باشد نه اینکه منتظر تایپ کردن کاربر بمانیم و سپس دکمه را غیر فعال کنیم. چنین کاری منطقی نیست. بنابراین به جای error می توانیم از invalid استفاده کنیم:

<button type="submit" :disabled="$v.$invalid">Submit</button>

با این کار دکمه submit از همان ابتدای کار غیر فعال می باشد. بنابراین کاربر باید تمام موارد فرم را درست پر کند تا این دکمه فعال شود.

اعتبارسنجی ناهمگام (async validation)

اعتبارسنجی های ناهمگام یا نامتقارن (asynchronous) به اعتبارسنجی هایی می گویند که به سرور وابسته است بنابراین تمام کار هایی که تا این قسمت انجام داده ایم، اعتبارسنجی همگام (synchronous) بوده است. اگر یادتان باشد برایتان توضیح داده بودم که firebase ایمیل های تکراری را برای ثبت نام قبول نمی کند بنابراین این یک فرصت عالی برای بررسی ایمیل از سمت firebase و نمایش فیدبک در UI است. برای انجام این کار باید validator های شخصی خود را بسازیم چرا که validator ای از پیش برای این کار تعریف نشده است. برای این کار به rule set مربوط به email رفته و نامی برای validator خود انتخاب می کنم. من unique (به معنی «یکتا» یا «منحصر به فرد») را انتخاب می کنم که نشان دهنده تکراری نبودن ایمیل است اما شما می توانید هر چیز دیگری را انتخاب کنید. validator ها در ساده ترین حالت یک تابع هستند بنابراین می توان گفت:

email: {
  required,
  email,
  unique: val => {
    
  }
}

val (یا هر نام دیگر که شما برایش بگذارید) همان مقدار موجود در input مربوطه (در اینجا، ایمیل تایپ شده) است که به صورت خودکار توسط vuelidate پاس داده می شود. شما باید درون این تابع true یا false را برگردانید. مثلا اگر بخواهیم به صورت محلی و بدون اتصال به firebase کار کنیم، به راحتی می گوییم:

email: {
  required,
  email,
  unique: val => {
    return val !== "roxo3@info.ir";
  }
},

یعنی ایمیل من نباید roxo3@info.ir باشد. در واقع اگر val (ایمیل تایپ شده) برابر نباشد، شرط صحیح بوده و true برگردنده می شود و در غیر این صورت شرط غلط بوده و false برگردانده می شود. حالا اگر به مرورگر بروید و هر ایمیلی به جز roxo3@info.ir را وارد کنید، تایید می شود اما roxo3@info.ir خطا می دهد. حالا بیایید کمی این کد را بهتر کنیم:

email: {
  required,
  email,
  unique: val => {
    if (val === "") return true;
    return new Promise((resolve, reject) => {
      resolve(val !== "roxo3@info.ir");
    });
  }
},

در ابتدا یک شرط if نوشته و گفته ام اگر Val یک رشته خالی بود true را برگردان. چرا؟ این کار دو دلیل اصلی دارد:

  • اولا اگر یک رشته خالی داشتیم، یعنی کاربر چیزی را تایپ نکرده است یا اگر قبلا چیزی وجود داشته است، توسط کاربر پاک شده است. بنابراین چرا باید یک رشته خالی را برای اعتبارسنجی به سمت سرور ارسال کنیم؟ مشخص است که رشته های خالی نباید اعتبارسنجی شوند.
  • دوما چرا false را return نکنیم؟ به دلیل اینکه کار unique بررسی تکراری بودن یک ایمیل است نه وجود ایمیل! وجود ایمیل و معتبر بودن ساختار آن توسط دو validator دیگر ما به نام های required و email بررسی می شوند. اگر ما در unique مقدار false را برگردانیم، انگار گفته ایم که این ایمیل تکراری است! و یک رشته خالی نمی تواند در پایگاه داده ما ثبت شود چه برسد که تکراری باشد. سعی کنید validator های خود را با هم قاطی نکنید!

در ادامه کد یک Promise را ساخته ام. ساختار vuelidate بدین صورت است که اگر بخواهید validator های خود را به صورت async داشته باشید باید یک Promise برگردانید (گرچه که کد بالا هنوز async نیست). من انتظار دارم که شما با Promise ها آشنا باشید چرا که از مباحث جاوا اسکریپت هستند و ربطی به Vue ندارند. اگر با آن ها آشنایی ندارید کلمه Promise را در روکسو پلاس جست و جو کرده و مقالات مختلف ما را مطالعه کنید. هر promise یک resolve و یک reject می گیرد که به ترتیب برای قبول کردن و رد کردن درخواست استفاده می شوند. بنابراین کد بالا می گوید اگر val برابر roxo3@info.ir نبود،

برای اینکه بتوانیم واقعا به firebase چیزی را ارسال کنیم باید index را در Firebase تعریف کنیم. برای این کار به پایگاه داده Firebase خودتان رفته و سربرگ rules را به شکل زیر تغییر دهید:

{
  "rules": {
    ".read": "true",
    ".write": "auth != null",
      "users": {
        ".indexOn": ["email"]
      }
  }
}

خصوصیت indexOn به firebase می گوید به ما اجازه بدهد تا بر اساس email کاربران را جست و جو کنیم. همچنین read را روی true گذاشته ام تا مجبور به گرفتن توکن و login شدن نباشیم. حالا به جای اینکه Promise را خودمان ساخته و برگردانیم، می توانیم از Promise برگردانده شده از سمت Firebase استفاده کنیم. برای این کار ابتدا axios را import می کنیم:

<script>
import {
  required,
  email,
  numeric,
  minValue,
  minLength,
  sameAs,
  requiredUnless
} from "vuelidate/lib/validators";
import axios from "axios";

سپس باید به firebase کوئری بزنیم که آیا ایمیل وارد شده توسط کاربر قبلا در پایگاه داده ثبت شده است یا خیر؟ اگر ایمیل ثبت شده باشد، پاسخ برگردانده شده از Firebase دارای قسمتی به نام Data است که آن کاربر را به شکل یک شیء جاوا اسکریپتی برمی گرداند اما اگر وجود نداشته باشد، قسمت data خالی خواهد بود. بنابراین:

email: {
  required,
  email,
  unique: val => {
    if (val === "") return true;
    return axios
      .get('/users.json?orderBy="email"&equalTo="' + val + '"')
      .then(res => {
        return Object.keys(res.data).length === 0;
      });
  }
},

در اینجا با متد Get از Axios به آدرس user.json یک کوئری ارسال کرده ام (اگر از فصل قبل یادتان بیاید، ابتدای آدرس در فایل main.js ذخیره شده است). کوئری ما می گوید orderBy (یعنی «مرتب کن بر اساس») و سپس email را به آن پاس داده ایم که همان فیلد email در پایگاه داده برای کاربران است. سپس گفته ایم equalTo (یعنی «برابر است با») و Val (ایمیل تایپ شده توسط کاربر) را به آن داده ایم. هم email و هم val باید درون double quotation قرار بگیرند و این موضوع از قوانین firebase است. سپس یک promise به ما برگردانده می شود که با Then آن را گرفته و بررسی می کنیم. متدی به نام keys در شیء Object در جاوا اسکریپت وجود دارد (ربطی به Vue ندارد) که key های یک شیء را به ما می دهد. از طرفی گفتم که اگر ایمیل تکراری نباشد، قسمت data در پاسخ firebase حتما خالی است بنابراین می گوییم اگر promise برگردانده شده از سمت Firebase هیچ کلیدی نداشته باشد (length یا تعداد کلیدها برابر 0 بود) باید true برگردانده شود. در واقع کل این شرط به true یا false تغییر می کند و return خواهد شد. به راحتی می توانید این کد را در مرورگر خود تست کنید (یادتان باشد که firebase در ایران تحریم است و ابزار ضد تحریم شما باید روشن باشد).

هشدار: ما بررسی ایمیل را روی رویداد blur انجام می دهیم اما اگر آن را روی رویداد change انجام بدهید (با هر بار فشردن کلیدهای کیبورد) درخواست های بسیار زیادی به سرور خودتان ارسال کرده و آن را شدیدا درگیر می کنید. حواستان باشد که از چنین اشتباهاتی دوری کنید.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش رایگان Vue js از صفر تا صد توصیه می‌کند:
نویسنده شوید

دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.