اعتبارسنجی فرم ها
در سالهای اولیهی پیدایش زبان جاوا اسکریپت، یکی از مهمترین کاربردهای این زبان اعتبارسنجی فرمها (Forms Validation) بود. منظور از اعتبارسنجی، بررسی دادههای وارد شده در فیلدهای فرم، قبل از ارسال به سرور است. تا از ارسال اطلاعات غلط به سرور تا حد امکان جلوگیری شود.
البته هنوز هم اعتبارسنجی فرمها یکی از کاربردهای جاوا اسکریپت است. اما نمیتوان آن را جزء مهمترین کاربردهای جاوا اسکریپت دانست. در سالهای اولیهی پیدایش جاوا اسکریپت، سرعت انتقال اطلاعات بر روی شبکهی اینترنت بسیار پایین بود و به همین دلیل بارگذاری یک صفحهی وب معمولاً نیاز به زمان زیادی داشت. در صورتی که کاربر اطلاعات غلطی را در فرم وارد کرده و ارسال میکرد؛ این اطلاعات در سرور پردازش میشد و خطاهای موجود در دادههای ارسالی، جهت اصلاح به کاربر اطلاع داده میشد. اما برای اطلاعرسانی خطاها به کاربر، باید کل صفحهی وب مجدداً بارگذاری میشد. در نتیجه هر بار ارسال فرم با اطلاعات غلط، هم موجب انتظار کاربر برای بارگذاری مجدد صفحه میشد. و هم باعث تحمیل دوبارهی بار پردازش فرم به سرور میشد که میتوانست موجب کندی سرعت پاسخگویی سرور شود.
برای جلوگیری از ارسال اطلاعات غلط به سرور، میتوان قبل از ارسال فرم، با استفاده از جاوا اسکریپت دادههای وارد شده در فیلدهای فرم را اعتبارسنجی کرد. البته اعتبارسنجی فرمها با جاوا اسکریپت صرفاً برای راحتی کاربر و کم کردن فشار بر روی سرور انجام میشود. یعنی اعتبارسنجی در سرور در هر صورت باید انجام شود و اعتبارسنجی با جاوا اسکریپت به تنهایی کافی نیست. اعتبارسنجی در سرور بنا به دلایل امنیتی ضروری است. زیرا اعتبارسنجی در مرورگر که با جاوا اسکریپت انجام میشود، با روشهای مختلف قابل دور زدن (Bypass) است. ضمناً اعتبارسنجی برخی فیلدها فقط در سرور امکانپذیر است. مثلاً بررسی تکراری بودن یک نام کاربری یا یک ایمیل به تنهایی با جاوا اسکریپت امکانپذیر نیست. زیرا برای این اعتبارسنجی باید به دادههای ذخیره شده در پایگاه دادهی سرور دسترسی داشت.
هرچند پیش از این نیز تا حدودی در مورد اعتبارسنجی صحبت شده و مثالهایی نیز در این رابطه ارائه شده است. اما در این بخش با جزئیات بیشتری به این موضوع خواهیم پرداخت. توجه کنید که در HTML نیز امکاناتی جهت اعتبارسنجی فرمها وجود دارد. مثلاً با استفاده از صفت required میتوان پر کردن یک فیلد را برای ارسال فرم اجباری کرد. و یا با صفت pattern میتوان الگوی خاصی را با یک عبارت منظم برای رشتهی وارد شده در یک فیلد متنی تعیین کرد. اما در این بخش از امکانات HTML صرف نظر میکنیم و اعتبارسنجی فرمها را صرفاً با جاوا اسکریپت انجام خواهیم داد. زیرا اولاً رفتار مرورگرهای مختلف در این رابطه یکسان نیست. و ثانیاً در اکثر مواقع لازم است تا پیامهای خطایی که به کاربر نمایش داده میشوند، سفارشی شوند. که انجام این کار فقط با جاوا اسکریپت امکانپذیر است.
بررسی تعداد کاراکترهای وارد شده
حتماً تا به حال با فرمهایی که پر کردن برخی از فیلدهایشان اختیاری و برخی دیگر اجباری است برخورد داشتهاید. فیلدهایی که پر کردن آنها اجباری است را باید قبل از ارسال فرم به سرور اعتبارسنجی کرد که حتماً مقداری در آنها وارد شده باشد. همچنین در برخی فیلدها ممکن است تعداد کاراکترهای وارد شده نیز دارای محدودیت باشد. مثلاً در یک وبسایت ممکن است تعداد کاراکترهای نام کاربری بین ۵ تا ۱۵ کاراکتر باشد و رشتههایی که طول کمتر از ۵ و یا بیشتر از ۱۵ کاراکتر دارند به عنوان نام کاربری قابل قبول نباشند.
برای بررسی تعداد کاراکترهای وارد شده در یک فیلد میتوان از خاصیت value استفاده کرد. این خاصیت یک رشته است و مانند تمام دادههای رشتهای خاصیتی به نام length دارد که طول آن را مشخص میکند. به عنوان مثال در فرم زیر دو فیلد متنی برای دریافت نام کاربری و کلمهی عبور قرار دارد.
<form>
<label>نام کاربری</label>
<input type="text" name="user" id="user" /><br /><br />
<label>کلمهی عبور</label>
<input type="password" name="pass" id="pass" /><br /><br />
<button type="submit">ورود</button>
</form>
فرض کنید تعداد کاراکترهای مجاز برای نام کاربری ۵ تا ۱۵ کاراکتر، و برای کلمهی عبور ۶ تا ۲۰ کاراکتر است. در این صورت میتوان از برنامهی زیر برای اعتبارسنجی این فرم استفاده کرد.
const form = document.querySelector('form');
form.addEventListener('submit' , validate);
function validate(event){
const user = document.getElementById('user');
const pass = document.getElementById('pass');
if(user.value.length < 5 || user.value.length > 15){
alert('نام کاربری باید 5 تا 15 کاراکتر باشد');
event.preventDefault();
}else if(pass.value.length < 6 || pass.value.length > 20){
alert('کلمهی عبور باید 6 تا 20 کاراکتر باشد');
event.preventDefault();
}
}
این برنامه را میتوانید اینجا در CodePen اجرا کنید. این برنامه را اجرا کنید و دو مقدار نامعتبر را در دو فیلد نام کاربری و کلمهی عبور وارد کرده و فرم را ارسال کنید. مشاهده خواهید کرد که فقط یک پیام خطا که مربوط به فیلد نام کاربری است نمایش داده خواهد. یعنی پیام خطای مربوط به کلمهی عبور فقط در صورتی نمایش داده خواهد شد که مقدار وارد شده در فیلد نام کاربری معتبر باشد. دلیل این رفتار استفاده از ساختار if..elseif است. یعنی قسمت elseif فقط زمانی بررسی میشود که شرط مقابل if دارای مقدار false باشد. در نتیجه در صورت وجود خطا در فیلد نام کاربری که موجب true شدن شرط مقابل if میشود، قسمت elseif بررسی نمیشود.
اما معمولاً این رفتار مناسبی نیست. به خصوص اگر تعداد فیلدها زیاد باشد. معمولاً بهتر است تمام خطاهای موجود در فرم به کاربر نمایش داده شوند تا کاربر پس از رفع تمام مشکلات مجدداً روی دکمهی submit کلیک کند. برای حل این مشکل کافی است به جای یک ساختار if..elseif برای تمام فیلدها، از یک ساختار if برای هر یک از فیلدها به صورت مجزا استفاده کنیم. پس میتوان برنامهی فوق را به صورت زیر بازنویسی کرد.
const form = document.querySelector('form');
form.addEventListener('submit' , validate);
function validate(event){
const user = document.getElementById('user');
const pass = document.getElementById('pass');
if(user.value.length < 5 || user.value.length > 15){
alert('نام کاربری باید 5 تا 15 کاراکتر باشد');
event.preventDefault();
}
if(pass.value.length < 6 || pass.value.length > 20){
alert('کلمهی عبور باید 6 تا 20 کاراکتر باشد');
event.preventDefault();
}
}
در صورت اجرای این برنامه و وارد کردن مقادیر نامعتبر در هر دو فیلد نام کاربری و کلمهی عبور، دو پیام خطای مجزا با تابع alert به کاربر نمایش داده میشود.
نمایش پیام خطا در کنار فیلد
معمولاً بهتر است به جای استفاده از تابع alert برای نمایش پیامهای خطا، پیام خطای هر فیلد را در کنار همان فیلد نمایش دهیم. زیرا استفادهی زیاد از تابع alert به شدت برای کاربر آزار دهنده است. ضمناً تابع alert موجب توقف اجرای برنامه میشود که در برخی شرایط میتواند عملکرد یک برنامه را کاملاً مختل کند. پس بهتر است در کنار هر فیلد، یک عنصر خالی (مثلاً یک <span>) قرار دهیم تا در صورت نیاز پیام خطا را داخل آن (معمولاً با رنگ قرمز) نمایش دهیم.
فرم مثال قبلی را میتوان به شکل زیر بازنویسی کرد تا بتوان هر پیام خطایی را در کنار فیلد مربوطه نمایش داد.
<form>
<label>نام کاربری</label>
<input type="text" name="user" id="user" />
<span id="usererror"></span><br /><br />
<label>کلمهی عبور</label>
<input type="password" name="pass" id="pass" />
<span id="passerror"></span><br /><br />
<button type="submit">ورود</button>
</form>
حال میتوان برنامهی قبلی را به صورت زیر اصلاح کرد، تا در صورت وارد کردن مقدار نامعتبر در هر یک از فیلدها، پیام خطای مناسب در کنار همان فیلد به کاربر نمایش داده شود.
const form = document.querySelector('form');
form.addEventListener('submit' , validate);
function validate(event){
const user = document.getElementById('user');
const pass = document.getElementById('pass');
const usererror = document.getElementById('usererror');
const passerror = document.getElementById('passerror');
usererror.textContent = '';
passerror.textContent = '';
if(user.value.length < 5 || user.value.length > 15){
usererror.textContent = 'نام کاربری باید 5 تا 15 کاراکتر باشد';
event.preventDefault();
}
if(pass.value.length < 6 || pass.value.length > 20){
passerror.textContent ='کلمهی عبور باید 6 تا 20 کاراکتر باشد';
event.preventDefault();
}
}
این برنامه را میتوانید اینجا اجرا کنید. به دستورات خطوط ۹ و ۱۰ دقت کنید. از این دستورات برای حذف کردن پیامهایی که در اعتبارسنجی قبلی در عناصر <span> قرار گرفتهاند استفاده شده است. مثلاً ممکن است در اولین تلاش کاربر برای ارسال فرم، هر دو فیلد دارای مقدار نامعتبر باشند. پس باید در کنار هر دو فیلد پیامی نمایش داده شود. اما کاربر ممکن است یکی از این خطاها را برطرف کرده و مجدداً روی دکمهی "ورود" کلیک کند. در این صورت باید فقط یک پیام خطا به کاربر نمایش داده شود. پس باید قبل از اعتبارسنجی، تمام پیامهای قبلی را حذف کنیم. سپس اعتبارسنجی را انجام داده و در صورت وجود خطا در هر یک از فیلدها، پیام مناسب را در کنار همان فیلد نمایش دهیم. شکل زیر نتیجهی اجرای این مثال با مقادیر نامعتبر در هر دو فیلد متنی را نشان میدهد.
بررسی عددی بودن مقدار ورودی
در بعضی از فیلدهای متنی، فقط وارد کردن مقادیر عددی مجاز است. پس لازم است در زمان ارسال فرمها، از عددی بودن مقدار وارد شده مطمئن شویم. برای انجام این نوع اعتبارسنجی روشهای مختلفی وجود دارد. مثلاً میتوان از تابع isNaN برای بررسی عددی بودن مقدار ورودی استفاده کرد. این تابع در صورتی که مقدار ورودی یک عدد معتبر باشد مقدار false و در غیر این صورت مقدار true را بازمیگرداند. توجه کنید که برای این تابع نوع عدد مهم نیست. یعنی برای اعداد صحیح، اعشاری، دودویی و سایر روشهای نمایش اعداد در جاوا اسکریپت مقدار false را بازمیگرداند. مثلاً رشتهی "3e-4" از نظر این تابع یک عدد است و در صورت ارسال این رشته به تابع isNaN مقدار false بازگردانده میشود.
در صورتی که فقط اعداد صحیح معتبر باشند، میتوان از متدهایی مانند Number.isInteger و Math.floor استفاده کرد. به عنوان مثال فرم زیر را در نظر بگیرید که یک فیلد برای دریافت سال تولد دارد. مقدار وارد شده در این فیلد حتماً باید یک عدد صحیح و بین ۱۳۰۰ تا ۱۴۰۰ باشد.
<form>
<label>سال تولد</label>
<input type="text" name="year" id="year" />
<span id="yearerror"></span><br /><br />
<button type="submit">ارسال</button>
</form>
برای اعتبارسنجی این فرم میتوان از برنامهی زیر استفاده کرد.
const form = document.querySelector('form');
form.addEventListener('submit' , validate);
function validate(event){
const year = document.getElementById('year');
const yearerror = document.getElementById('yearerror');
yearerror.textContent = '';
if(!Number.isInteger(Number(year.value))){
yearerror.textContent = 'سال تولد باید یک عدد صحیح باشد';
event.preventDefault();
}else if(year.value < 1300 || year.value > 1400){
yearerror.textContent = 'سال تولد باید بین 1300 تا 1400 باشد';
event.preventDefault();
}
}
این برنامه را میتوانید اینجا اجرا کنید. با ارسال فرم موجود در این مثال، در صورتی که مقدار وارد شده یک عدد صحیح نباشد پیام خطای اول نمایش داده میشود. و در صورتی که مقدار وارد شده بین ۱۳۰۰ تا ۱۴۰۰ نباشد پیام خطای دوم نمایش داده میشود. شاید این تصور برای شما پیش آمده باشد که فقط بررسی شرط دوم برای این مثال کافی است. زیرا در صورتی که مقدار ورودی عددی نباشد، قطعاً در بازهی ۱۳۰۰ تا ۱۴۰۰ هم نیست. پس نیازی به بررسی شرط اول برای تشخیص عددی بودن یا نبودن آن نداریم.
اما این تصور درستی نیست. زیرا شرط اول نه تنها عددی بودن، بلکه صحیح بودن را نیز بررسی میکند. یعنی اگر فقط از شرط دوم استفاده شود، اعدادی که در بازهی ۱۳۰۰ تا ۱۴۰۰ هستند، اما صحیح نیستند نیز به عنوان ورودی معتبر شناخته میشوند. مثلاً به ازای ورودی ۱۳۳۲.۳۳ هیچ خطایی رخ نخواهد داد. پس وجود شرط اول برای بررسی صحیح بودن عدد لازم است.
البته این برنامه هنوز یک اشکال مهم دارد. فرض کنید کاربر رشتهی "0b10100101000" و یا رشتهی "132e1" را وارد کند. این دو رشته وقتی توسط تابع Number به نوع عددی تبدیل میشوند، هر دو به مقدار صحیح ۱۳۲۰ تبدیل میشوند. در نتیجه برنامهی فوق هیچ پیام خطایی را نمایش نداده و فرم ارسال میشود. در صورتی که قالب اعداد وارد شده نیز مهم باشد. یعنی فقط اعداد دهدهی قابل قبول باشند (معمولاً به همین صورت است). از روش فوق نمیتوان برای اعتبارسنجی استفاده کرد. و باید از روشی استفاده شود که کاراکترهای وارد شده را نیز بررسی کند. برای این منظور میتوان از عبارات منظم استفاده کرد. البته بدون عبارات منظم نیز میتوان کاراکترهای وارد شده را بررسی کرد. اما استفاده از عبارات منظم کار را بسیار سادهتر میکند.
اعتبارسنجی با عبارات منظم
عبارات منظم قدرتمندترین روش برای اعتبارسنجی فرمها هستند. البته به نسبت روشهای قبلی کمی پیچیدهتر نیز هستند. در این بخش قصد نداریم به معرفی عبارات منظم بپردازیم و فرض بر این است که خواننده با عبارات منظم آشنایی دارد. زیرا معرفی کامل عبارات منظم به یک کتاب مجزا نیاز دارد.
مثال قبلی را در نظر بگیرید. برای بررسی اینکه عدد وارد شده حتماً یک عدد صحیح و در مبنای ۱۰ باشد، میتوان با استفاده از عبارات منظم بررسی کرد که آیا تمام کاراکترهای تشکیل دهندهی آن، ارقام بین ۰ تا ۹ هستند یا خیر؟ هر کاراکتری غیر از ارقام ۰ تا ۹ در مقدار وارد شده وجود داشته باشد، قطعاً آن مقدار نمیتواند یک عدد صحیح در مبنای ۱۰ باشد. برنامهی مثال قبلی را میتوان به این صورت بازنویسی کرد.
const form = document.querySelector('form');
form.addEventListener('submit' , validate);
function validate(event){
const year = document.getElementById('year');
const yearerror = document.getElementById('yearerror');
yearerror.textContent = '';
if(!/^\d+$/.test(year.value)){
yearerror.textContent = 'سال تولد باید یک عدد صحیح باشد';
event.preventDefault();
}else if(year.value < 1300 || year.value > 1400){
yearerror.textContent = 'سال تولد باید بین 1300 تا 1400 باشد';
event.preventDefault();
}
}
این مثال را میتوانید اینجا اجرا کنید. در این مثال برای بررسی صحیح بودن یک عدد از عبارت منظم "/^\d+$/" استفاده شده است. این عبارت منظم فقط با رشتهای مطابقت میکند که تمام کاراکترهای آن از ارقام ۰ تا ۹ تشکیل شده باشند. پس ورودیهایی مانند "0b111010" یا "3e2" معتبر نخواهند بود. البته در برخی موارد ممکن است اعداد صحیح دهدهی نیاز به علامت مثبت یا منفی نیز داشته باشند. در این صورت باید عبارت منظم را کمی تغییر دهیم. عبارت منظم "/^[+-]?\d+$/" این اجازه را میدهد که اولین کاراکتر مقدار ورودی، علامت مثبت یا منفی باشد.
به عنوان یک مثال کمی پیچیدهتر فرم زیر را در نظر بگیرید که یک فیلد متنی برای دریافت ایمیل کاربر در آن وجود دارد. میدانیم که ایمیلهای معتبر دارای قالب خاصی هستند و هر رشتهای نمیتواند یک ایمیل معتبر باشد. پس لازم است تا قبل از ارسال فرم به سرور، مقدار وارد شده در این فیلد را اعتبارسنجی کنیم.
<form>
<label>ایمیل</label>
<input type="text" name="email" id="email" />
<span id="emailerror"></span><br /><br />
<button type="submit">ارسال</button>
</form>
برای اعتبارسنجی این فرم نیز میتوان از عبارات منظم استفاده کرد. برنامهی زیر این کار را انجام میدهد.
const form = document.querySelector('form');
form.addEventListener('submit' , validate);
function validate(event){
const email = document.getElementById('email');
const emailerror = document.getElementById('emailerror');
const simpleEmail = /^[a-z0-9._-]+@[a-z0-9.-]+\.[a-z]{2,4}$/;
emailerror.textContent = '';
if(!simpleEmail.test(email.value)){
emailerror.textContent = 'لطفاً یک ایمیل معتبر وارد کنید';
event.preventDefault();
}
}
این برنامه را میتوانید اینجا اجرا کنید. با اجرای این مثال مشاهده خواهید کرد که فقط در صورت وارد کردن یک ایمیل معتبر میتوانید فرم را ارسال کنید. ضمناً برای سادگی از یک عبارت منظم نسبتاً ساده استفاده شده است. در نتیجه در برخی موارد خاص ممکن است این برنامه عملکرد صحیحی نداشته باشد. مثلاً رشتهی ".@..com" از نظر این برنامه یک ایمیل معتبر است. در صورت نیاز میتوانید از عبارات منظم پیچیدهتری استفاده کنید که این حالتهای خاص را نیز پوشش دهند. همچنین میتوانید از عبارات منظم در کنار روشهای معمولی استفاده کنید. مثلاً میتوانید در شرط موجود در ساختار if، شرط "email.value.length < 10" را نیز با عملگر "||" اضافه کنید تا رشتههایی که طول کمتر از ۱۰ دارند به عنوان ایمیل معتبر شناخته نشوند.