# Bina Aplikasi Perbankan Bahagian 3: Kaedah Mengambil dan Menggunakan Data ## Kuiz Pra Kuliah [Kuiz Pra Kuliah](https://calm-wave-0d1a32b03.1.azurestaticapps.net/quiz/45) ### Pengenalan Inti setiap aplikasi web ada *data*. Data boleh dilakukan dalam pelbagai bentuk, tetapi tujuan utamanya adalah untuk menunjukkan maklumat kepada pengguna. Dengan aplikasi web menjadi semakin interaktif dan kompleks, bagaimana pengguna mengakses dan berinteraksi dengan maklumat kini menjadi bahagian penting dalam pembangunan web. Dalam pelajaran ini, kita akan melihat cara mengambil data dari pelayan secara asinkron, dan menggunakan data ini untuk memaparkan maklumat di laman web tanpa memuatkan semula HTML. ### Prasyarat Anda perlu membina bahagian [Borang Log Masuk dan Pendaftaran](../2-forms/README.md) dari aplikasi web untuk pelajaran ini. Anda juga perlu memasang [Node.js](https://nodejs.org) dan [jalankan API pelayan](../api/README.md) secara tempatan supaya anda mendapat data akaun. Anda boleh menguji bahawa pelayan berjalan dengan betul dengan menjalankan perintah ini di terminal: ```sh curl http://localhost:5000/api # -> harus mengembalikan "Bank API v1.0.0" sebagai hasilnya ``` --- ## AJAX dan pengambilan data Laman web tradisional mengemas kini kandungan yang dipaparkan ketika pengguna memilih pautan atau mengirimkan data menggunakan borang, dengan memuatkan semula halaman HTML penuh. Setiap kali data baru dimuat, pelayan web mengembalikan halaman HTML baru yang perlu diproses oleh penyemak imbas, mengganggu tindakan pengguna semasa dan membatasi interaksi semasa muat semula. Alur kerja ini juga disebut *Aplikasi Multi-Halaman* atau *MPA*. ![Kemas kini aliran kerja dalam aplikasi berbilang halaman](./images/mpa.png) Ketika aplikasi web mula menjadi lebih kompleks dan interaktif, teknik baru yang disebut [AJAX (Asynchronous JavaScript and XML)](https://en.wikipedia.org/wiki/Ajax_(programming)) muncul. Teknik ini membolehkan aplikasi web mengirim dan mengambil data dari pelayan secara asinkron menggunakan JavaScript, tanpa harus memuat semula halaman HTML, menghasilkan kemas kini yang lebih cepat dan interaksi pengguna yang lebih lancar. Apabila data baru diterima dari pelayan, halaman HTML semasa juga dapat diperbarui dengan JavaScript menggunakan API [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model). Dari masa ke masa, pendekatan ini telah berkembang menjadi apa yang sekarang disebut [*Aplikasi Halaman Tunggal* atau *SPA*](https://en.wikipedia.org/wiki/Single-page_application). ![Kemas kini alur kerja dalam aplikasi satu halaman](./images/spa.png) Semasa AJAX pertama kali diperkenalkan, satu-satunya API yang tersedia untuk mengambil data secara asinkron adalah [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest). Tetapi penyemak imbas moden kini juga melaksanakan [`Fetch` API](https://developer.mozilla.org/docs/Web/API/Fetch_API), yang menggunakan janji dan lebih sesuai untuk dimanipulasi Data JSON. > Walaupun semua penyemak imbas moden menyokong `Fetch API`, jika anda mahu aplikasi web anda berfungsi pada penyemak imbas lama atau penyemak imbas lama, sebaiknya periksa [jadual keserasian di caniuse.com](https://caniuse.com/fetch) pertama. ### Tugas Dalam [pelajaran sebelumnya](../2-form/README.md) kami melaksanakan borang pendaftaran untuk membuat akaun. Kami sekarang akan menambahkan kod untuk log masuk menggunakan akaun yang ada, dan mengambil datanya. Buka fail `app.js` dan tambahkan fungsi `login` baru: ```js async function login() { const loginForm = document.getElementById('loginForm') const user = loginForm.user.value; } ``` Di sini kita mulakan dengan mengambil elemen borang dengan `getElementById()`, dan kemudian kita mendapat nama pengguna dari input dengan `loginForm.user.value`. Setiap kawalan borang dapat diakses dengan namanya (diatur dalam HTML menggunakan atribut `name`) sebagai harta bentuk. Dengan cara yang serupa dengan apa yang kami lakukan untuk pendaftaran, kami akan membuat fungsi lain untuk melakukan permintaan pelayan, tetapi kali ini untuk mengambil data akaun: ```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' }; } } ``` Kami menggunakan API `fetch` untuk meminta data secara tidak serentak dari pelayan, tetapi kali ini kami tidak memerlukan parameter tambahan selain URL untuk dipanggil, kerana kami hanya meminta data. Secara lalai, `fetch` membuat permintaan HTTP [`GET`](https://developer.mozilla.org/docs/Web/HTTP/Methods/GET), itulah yang kami cari di sini. ✅ `encodeURIComponent()` adalah fungsi yang melarikan diri daripada watak khas untuk URL. Masalah apa yang mungkin kita hadapi jika kita tidak memanggil fungsi ini dan menggunakan nilai `pengguna` secara langsung di URL? Sekarang mari kita kemas kini fungsi `login` kami untuk menggunakan `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'); } ``` Pertama, kerana `getAccount` adalah fungsi tak segerak, kita perlu memadankannya dengan kata kunci `await` untuk menunggu hasil pelayan. Seperti permintaan pelayan, kami juga harus menangani kes ralat. Buat masa ini kami hanya akan menambahkan mesej log untuk memaparkan ralat, dan kembali kepadanya kemudian. Kemudian kita harus menyimpan data di suatu tempat sehingga nanti kita dapat menggunakannya untuk memaparkan maklumat papan pemuka. Oleh kerana pemboleh ubah `account` belum ada, kami akan membuat pemboleh ubah global untuknya di bahagian atas fail kami: ```js let account = null; ``` Setelah data pengguna disimpan ke dalam variabel kita dapat menavigasi dari halaman *login* ke papan pemuka * menggunakan fungsi `navigate()` yang sudah kita miliki. Akhirnya, kita perlu memanggil fungsi `login` kita semasa borang log masuk dihantar, dengan mengubah HTML: ```html