# Bygg en bankapp del 3: Metoder for henting og bruk av data ## Quiz før forelesning [Quiz før forelesning](https://ff-quizzes.netlify.app/web/quiz/45) ### Introduksjon Kjernen i enhver webapplikasjon er *data*. Data kan ha mange former, men hovedformålet er alltid å vise informasjon til brukeren. Etter hvert som webapplikasjoner blir mer interaktive og komplekse, har måten brukeren får tilgang til og interagerer med informasjon blitt en viktig del av webutvikling. I denne leksjonen skal vi se hvordan man henter data fra en server asynkront og bruker disse dataene til å vise informasjon på en nettside uten å laste HTML på nytt. ### Forutsetninger Du må ha bygget [innloggings- og registreringsskjemaet](../2-forms/README.md) som en del av webappen for denne leksjonen. Du må også installere [Node.js](https://nodejs.org) og [kjøre server-APIet](../api/README.md) lokalt for å få kontodata. Du kan teste at serveren kjører riktig ved å utføre denne kommandoen i en terminal: ```sh curl http://localhost:5000/api # -> should return "Bank API v1.0.0" as a result ``` --- ## AJAX og datahenting Tradisjonelle nettsteder oppdaterer innholdet som vises når brukeren velger en lenke eller sender inn data via et skjema, ved å laste hele HTML-siden på nytt. Hver gang nye data må lastes, returnerer webserveren en helt ny HTML-side som må behandles av nettleseren, noe som avbryter brukerens handling og begrenser interaksjoner under omlastingen. Denne arbeidsflyten kalles også en *Multi-Page Application* eller *MPA*.  Da webapplikasjoner begynte å bli mer komplekse og interaktive, dukket en ny teknikk opp kalt [AJAX (Asynchronous JavaScript and XML)](https://en.wikipedia.org/wiki/Ajax_(programming)). Denne teknikken lar webapper sende og hente data fra en server asynkront ved hjelp av JavaScript, uten å laste HTML-siden på nytt, noe som resulterer i raskere oppdateringer og jevnere brukerinteraksjoner. Når nye data mottas fra serveren, kan den nåværende HTML-siden også oppdateres med JavaScript ved hjelp av [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model)-APIet. Over tid har denne tilnærmingen utviklet seg til det som nå kalles en [*Single-Page Application* eller *SPA*](https://en.wikipedia.org/wiki/Single-page_application).  Da AJAX først ble introdusert, var det eneste APIet tilgjengelig for å hente data asynkront [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest). Men moderne nettlesere implementerer nå det mer praktiske og kraftige [`Fetch` API](https://developer.mozilla.org/docs/Web/API/Fetch_API), som bruker promises og er bedre egnet til å manipulere JSON-data. > Selv om alle moderne nettlesere støtter `Fetch API`, er det alltid lurt å sjekke [kompatibilitetstabellen på caniuse.com](https://caniuse.com/fetch) først hvis du vil at webapplikasjonen din skal fungere på eldre nettlesere. ### Oppgave I [forrige leksjon](../2-forms/README.md) implementerte vi registreringsskjemaet for å opprette en konto. Nå skal vi legge til kode for å logge inn med en eksisterende konto og hente dens data. Åpne `app.js`-filen og legg til en ny `login`-funksjon: ```js async function login() { const loginForm = document.getElementById('loginForm') const user = loginForm.user.value; } ``` Her starter vi med å hente skjemaelementet med `getElementById()`, og deretter henter vi brukernavnet fra input-feltet med `loginForm.user.value`. Hvert skjemaelement kan nås via sitt navn (angitt i HTML med `name`-attributtet) som en egenskap av skjemaet. På samme måte som vi gjorde for registreringen, skal vi lage en annen funksjon for å utføre en serverforespørsel, men denne gangen for å hente kontodata: ```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' }; } } ``` Vi bruker `fetch`-APIet for å hente data asynkront fra serveren, men denne gangen trenger vi ingen ekstra parametere annet enn URLen vi skal kalle, siden vi kun henter data. Som standard oppretter `fetch` en [`GET`](https://developer.mozilla.org/docs/Web/HTTP/Methods/GET)-HTTP-forespørsel, som er det vi ønsker her. ✅ `encodeURIComponent()` er en funksjon som rømmer spesialtegn for URL. Hvilke problemer kan vi få hvis vi ikke kaller denne funksjonen og bruker verdien `user` direkte i URLen? La oss nå oppdatere `login`-funksjonen vår til å bruke `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'); } ``` Først, siden `getAccount` er en asynkron funksjon, må vi bruke `await`-nøkkelordet for å vente på serverresultatet. Som med enhver serverforespørsel, må vi også håndtere feiltilfeller. Foreløpig legger vi bare til en loggmelding for å vise feilen, og kommer tilbake til dette senere. Deretter må vi lagre dataene et sted slik at vi senere kan bruke dem til å vise informasjonen på dashbordet. Siden variabelen `account` ikke eksisterer ennå, oppretter vi en global variabel for den øverst i filen vår: ```js let account = null; ``` Etter at brukerdataene er lagret i en variabel, kan vi navigere fra *login*-siden til *dashboard*-siden ved hjelp av `navigate()`-funksjonen vi allerede har. Til slutt må vi kalle `login`-funksjonen vår når innloggingsskjemaet sendes inn, ved å endre HTML: ```html