# ساخت اپلیکیشن بانکی قسمت ۳: روشهای دریافت و استفاده از دادهها ## آزمون پیش از درس [آزمون پیش از درس](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' }; } } ``` ما از API `fetch` برای درخواست دادهها به صورت غیرهمزمان از سرور استفاده میکنیم، اما این بار به هیچ پارامتر اضافی به جز 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