# בניית אפליקציית בנקאות חלק 3: שיטות לשליפת נתונים ושימוש בהם ## חידון לפני השיעור [חידון לפני השיעור](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 (JavaScript ו-XML אסינכרוניים)](https://en.wikipedia.org/wiki/Ajax_(programming)). טכניקה זו מאפשרת לאפליקציות אינטרנט לשלוח ולקבל נתונים משרת בצורה אסינכרונית באמצעות JavaScript, מבלי לטעון מחדש את דף ה-HTML, מה שמוביל לעדכונים מהירים יותר ואינטראקציות חלקות יותר. כאשר מתקבלים נתונים חדשים מהשרת, ניתן גם לעדכן את דף ה-HTML הנוכחי באמצעות JavaScript באמצעות ה-[DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model) API. עם הזמן, גישה זו התפתחה למה שמכונה כיום [*אפליקציה חד-דפית* או *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), המשתמש ב-Promises ומתאים יותר לטיפול בנתוני 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