# ساخت یک اپلیکیشن بانکی - قسمت ۳: روشهای دریافت و استفاده از دادهها ## آزمون پیش از درس [آزمون پیش از درس](https://ff-quizzes.netlify.app/web/quiz/45) ### مقدمه در هستهی هر اپلیکیشن وب، *داده* وجود دارد. دادهها میتوانند اشکال مختلفی داشته باشند، اما هدف اصلی آنها همیشه نمایش اطلاعات به کاربر است. با پیچیدهتر و تعاملیتر شدن اپلیکیشنهای وب، نحوهی دسترسی و تعامل کاربر با اطلاعات به یکی از بخشهای کلیدی توسعه وب تبدیل شده است. در این درس، یاد میگیریم که چگونه دادهها را به صورت غیرهمزمان از یک سرور دریافت کنیم و از این دادهها برای نمایش اطلاعات در یک صفحه وب بدون بارگذاری مجدد HTML استفاده کنیم. ### پیشنیاز برای این درس، باید بخش [فرم ورود و ثبتنام](../2-forms/README.md) اپلیکیشن وب را ساخته باشید. همچنین باید [Node.js](https://nodejs.org) را نصب کرده و [سرور API](../api/README.md) را به صورت محلی اجرا کنید تا به دادههای حساب دسترسی داشته باشید. میتوانید با اجرای این دستور در یک ترمینال، بررسی کنید که سرور به درستی اجرا میشود: ```sh curl http://localhost:5000/api # -> should return "Bank API v1.0.0" as a result ``` --- ## AJAX و دریافت دادهها وبسایتهای سنتی زمانی که کاربر یک لینک را انتخاب میکند یا دادهای را از طریق فرم ارسال میکند، محتوای نمایش داده شده را با بارگذاری مجدد کل صفحه HTML بهروزرسانی میکنند. هر بار که نیاز به بارگذاری دادههای جدید باشد، سرور وب یک صفحه HTML کاملاً جدید بازمیگرداند که باید توسط مرورگر پردازش شود، که این کار باعث وقفه در عملکرد کاربر و محدود کردن تعاملات در طول بارگذاری میشود. این فرآیند به عنوان *اپلیکیشن چندصفحهای* یا *MPA* شناخته میشود.  با پیچیدهتر و تعاملیتر شدن اپلیکیشنهای وب، تکنیکی جدید به نام [AJAX (جاوااسکریپت و XML غیرهمزمان)](https://en.wikipedia.org/wiki/Ajax_(programming)) معرفی شد. این تکنیک به اپلیکیشنهای وب اجازه میدهد که دادهها را به صورت غیرهمزمان از سرور ارسال و دریافت کنند، بدون نیاز به بارگذاری مجدد صفحه HTML، که منجر به بهروزرسانی سریعتر و تعاملات روانتر کاربر میشود. زمانی که دادههای جدید از سرور دریافت میشود، صفحه HTML فعلی نیز میتواند با استفاده از API [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model) با جاوااسکریپت بهروزرسانی شود. با گذشت زمان، این رویکرد به چیزی که اکنون به عنوان [*اپلیکیشن تکصفحهای* یا *SPA*](https://en.wikipedia.org/wiki/Single-page_application) شناخته میشود، تکامل یافته است.  زمانی که AJAX برای اولین بار معرفی شد، تنها API موجود برای دریافت دادهها به صورت غیرهمزمان [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest) بود. اما مرورگرهای مدرن اکنون API قدرتمندتر و راحتتری به نام [`Fetch`](https://developer.mozilla.org/docs/Web/API/Fetch_API) را پیادهسازی کردهاند که از پرامیسها استفاده میکند و برای کار با دادههای JSON مناسبتر است. > در حالی که تمام مرورگرهای مدرن از `Fetch API` پشتیبانی میکنند، اگر میخواهید اپلیکیشن وب شما روی مرورگرهای قدیمی یا قدیمیتر کار کند، همیشه ایده خوبی است که ابتدا جدول سازگاری را در [caniuse.com](https://caniuse.com/fetch) بررسی کنید. ### وظیفه در [درس قبلی](../2-forms/README.md) فرم ثبتنام را برای ایجاد حساب کاربری پیادهسازی کردیم. اکنون کدی اضافه میکنیم تا با استفاده از یک حساب موجود وارد شویم و دادههای آن را دریافت کنیم. فایل `app.js` را باز کرده و یک تابع جدید به نام `login` اضافه کنید: ```js async function login() { const loginForm = document.getElementById('loginForm') const user = loginForm.user.value; } ``` در اینجا ابتدا عنصر فرم را با استفاده از `getElementById()` بازیابی میکنیم و سپس نام کاربری را از ورودی با `loginForm.user.value` دریافت میکنیم. هر کنترل فرم را میتوان با استفاده از نام آن (که در HTML با استفاده از ویژگی `name` تنظیم شده است) به عنوان یک ویژگی از فرم دسترسی داشت. مشابه آنچه برای ثبتنام انجام دادیم، یک تابع دیگر برای انجام درخواست سرور ایجاد میکنیم، اما این بار برای دریافت دادههای حساب: ```js async function getAccount(user) { try { const response = await fetch('//localhost:5000/api/accounts/' + encodeURIComponent(user)); return await response.json(); } catch (error) { return { error: error.message || 'Unknown error' }; } } ``` ما از `fetch` API برای درخواست دادهها به صورت غیرهمزمان از سرور استفاده میکنیم، اما این بار به هیچ پارامتر اضافی به جز URL نیاز نداریم، زیرا فقط در حال پرسوجوی دادهها هستیم. به طور پیشفرض، `fetch` یک درخواست HTTP [`GET`](https://developer.mozilla.org/docs/Web/HTTP/Methods/GET) ایجاد میکند که همان چیزی است که ما در اینجا به دنبال آن هستیم. ✅ `encodeURIComponent()` یک تابع است که کاراکترهای خاص را برای URL فرار میدهد. اگر این تابع را فراخوانی نکنیم و مستقیماً مقدار `user` را در URL استفاده کنیم، چه مشکلاتی ممکن است پیش بیاید؟ اکنون تابع `login` خود را بهروزرسانی میکنیم تا از `getAccount` استفاده کند: ```js async function login() { const loginForm = document.getElementById('loginForm') const user = loginForm.user.value; const data = await getAccount(user); if (data.error) { return console.log('loginError', data.error); } account = data; navigate('/dashboard'); } ``` ابتدا، از آنجا که `getAccount` یک تابع غیرهمزمان است، باید آن را با کلمه کلیدی `await` مطابقت دهیم تا منتظر نتیجه سرور بمانیم. همانطور که در هر درخواست سرور، باید با موارد خطا نیز برخورد کنیم. فعلاً فقط یک پیام لاگ برای نمایش خطا اضافه میکنیم و بعداً به آن بازمیگردیم. سپس باید دادهها را جایی ذخیره کنیم تا بعداً بتوانیم از آن برای نمایش اطلاعات داشبورد استفاده کنیم. از آنجا که متغیر `account` هنوز وجود ندارد، یک متغیر سراسری برای آن در بالای فایل خود ایجاد میکنیم: ```js let account = null; ``` پس از ذخیره دادههای کاربر در یک متغیر، میتوانیم از صفحه *ورود* به صفحه *داشبورد* با استفاده از تابع `navigate()` که قبلاً داریم، برویم. در نهایت، باید تابع `login` خود را هنگام ارسال فرم ورود فراخوانی کنیم، با اصلاح HTML: ```html