You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/no/7-bank-project/2-forms/README.md

18 KiB

Bygg en bankapp Del 2: Lag et innloggings- og registreringsskjema

Forhåndsquiz

Forhåndsquiz

Introduksjon

I nesten alle moderne webapplikasjoner kan du opprette en konto for å få ditt eget private område. Siden flere brukere kan få tilgang til en webapplikasjon samtidig, trenger du en mekanisme for å lagre hver brukers personlige data separat og velge hvilken informasjon som skal vises. Vi kommer ikke til å dekke hvordan man håndterer brukeridentitet sikkert, da det er et omfattende tema i seg selv, men vi skal sørge for at hver bruker kan opprette én (eller flere) bankkontoer i appen vår.

I denne delen skal vi bruke HTML-skjemaer for å legge til innlogging og registrering i webapplikasjonen vår. Vi skal se hvordan vi kan sende data til en server-API programmessig, og til slutt hvordan vi kan definere grunnleggende valideringsregler for brukerinput.

Forutsetninger

Du må ha fullført HTML-maler og ruting for webapplikasjonen i denne leksjonen. Du må også installere Node.js og kjøre server-API-et lokalt slik at du kan sende data for å opprette kontoer.

Merk deg dette Du vil ha to terminaler kjørende samtidig som beskrevet nedenfor:

  1. For hovedbankappen vi bygde i leksjonen HTML-maler og ruting
  2. For Bank APP server-API-et som vi nettopp satte opp.

Du må ha begge serverne oppe og kjørende for å kunne følge resten av leksjonen. De lytter på forskjellige porter (port 3000 og port 5000), så alt skal fungere fint.

Du kan teste at serveren kjører riktig ved å kjøre denne kommandoen i en terminal:

curl http://localhost:5000/api
# -> should return "Bank API v1.0.0" as a result

Skjema og kontroller

<form>-elementet kapsler inn en seksjon av et HTML-dokument der brukeren kan skrive inn og sende data med interaktive kontroller. Det finnes mange forskjellige brukergrensesnittkontroller (UI-kontroller) som kan brukes i et skjema, hvor de vanligste er <input> og <button>-elementene.

Det finnes mange forskjellige typer <input>. For eksempel, for å lage et felt der brukeren kan skrive inn brukernavnet sitt, kan du bruke:

<input id="username" name="username" type="text">

Attributtet name vil bli brukt som egenskapsnavn når skjemadataene sendes. Attributtet id brukes til å knytte en <label> til skjemaelementet.

Ta en titt på hele listen over <input>-typer og andre skjemakontroller for å få en idé om alle de innebygde UI-elementene du kan bruke når du bygger grensesnittet ditt.

Merk at <input> er et tomt element som du ikke skal legge til en matchende avslutningstag for. Du kan imidlertid bruke den selvlukkende <input/>-notasjonen, men det er ikke påkrevd.

<button>-elementet i et skjema er litt spesielt. Hvis du ikke spesifiserer attributtet type, vil det automatisk sende skjemadataene til serveren når det trykkes. Her er de mulige verdiene for type:

  • submit: Standard i et <form>, knappen utløser skjemaets sendingshandling.
  • reset: Knappen tilbakestiller alle skjemakontroller til sine opprinnelige verdier.
  • button: Tildeler ingen standardoppførsel når knappen trykkes. Du kan deretter tildele egendefinerte handlinger til den ved hjelp av JavaScript.

Oppgave

La oss starte med å legge til et skjema i login-malen. Vi trenger et brukernavn-felt og en Logg inn-knapp.

<template id="login">
  <h1>Bank App</h1>
  <section>
    <h2>Login</h2>
    <form id="loginForm">
      <label for="username">Username</label>
      <input id="username" name="user" type="text">
      <button>Login</button>
    </form>
  </section>
</template>

Hvis du ser nærmere etter, kan du legge merke til at vi også har lagt til et <label>-element her. <label>-elementer brukes til å legge til et navn på UI-kontroller, som vårt brukernavnfelt. Etiketter er viktige for lesbarheten av skjemaene dine, men gir også ekstra fordeler:

  • Ved å knytte en etikett til en skjemakontroll hjelper det brukere som bruker hjelpemiddelteknologier (som skjermlesere) med å forstå hvilken data de forventes å oppgi.
  • Du kan klikke på etiketten for å sette fokus direkte på det tilknyttede feltet, noe som gjør det enklere å nå på berøringsskjermbaserte enheter.

Tilgjengelighet på nettet er et veldig viktig tema som ofte blir oversett. Takket være semantiske HTML-elementer er det ikke vanskelig å lage tilgjengelig innhold hvis du bruker dem riktig. Du kan lese mer om tilgjengelighet for å unngå vanlige feil og bli en ansvarlig utvikler.

Nå skal vi legge til et andre skjema for registrering, rett under det forrige:

<hr/>
<h2>Register</h2>
<form id="registerForm">
  <label for="user">Username</label>
  <input id="user" name="user" type="text">
  <label for="currency">Currency</label>
  <input id="currency" name="currency" type="text" value="$">
  <label for="description">Description</label>
  <input id="description" name="description" type="text">
  <label for="balance">Current balance</label>
  <input id="balance" name="balance" type="number" value="0">
  <button>Register</button>
</form>

Ved å bruke attributtet value kan vi definere en standardverdi for et gitt felt. Legg også merke til at feltet for balance har typen number. Ser det annerledes ut enn de andre feltene? Prøv å samhandle med det.

Kan du navigere og samhandle med skjemaene kun ved hjelp av tastaturet? Hvordan ville du gjort det?

Sende data til serveren

Nå som vi har et funksjonelt brukergrensesnitt, er neste steg å sende dataene til serveren. La oss gjøre en rask test med vår nåværende kode: Hva skjer hvis du klikker på Logg inn- eller Registrer-knappen?

La du merke til endringen i nettleserens URL-seksjon?

Skjermbilde av nettleserens URL-endring etter å ha klikket på Registrer-knappen

Standardhandlingen for et <form> er å sende skjemaet til den nåværende server-URL-en ved hjelp av GET-metoden, og legge til skjemadataene direkte i URL-en. Denne metoden har imidlertid noen begrensninger:

  • Dataene som sendes er svært begrenset i størrelse (ca. 2000 tegn)
  • Dataene er direkte synlige i URL-en (ikke ideelt for passord)
  • Den fungerer ikke med filopplastinger

Derfor kan du endre den til å bruke POST-metoden, som sender skjemadataene til serveren i HTTP-forespørselens kropp, uten noen av de tidligere begrensningene.

Selv om POST er den mest brukte metoden for å sende data, i noen spesifikke scenarier er det bedre å bruke GET-metoden, for eksempel når du implementerer et søkefelt.

Oppgave

Legg til action- og method-egenskaper i registreringsskjemaet:

<form id="registerForm" action="//localhost:5000/api/accounts" method="POST">

Prøv nå å registrere en ny konto med navnet ditt. Etter å ha klikket på Registrer-knappen, bør du se noe som dette:

Et nettleservindu på adressen localhost:5000/api/accounts, som viser en JSON-streng med brukerdata

Hvis alt går bra, skal serveren svare på forespørselen din med en JSON-respons som inneholder kontodataene som ble opprettet.

Prøv å registrere deg igjen med samme navn. Hva skjer?

Sende data uten å laste siden på nytt

Som du sikkert la merke til, er det et lite problem med tilnærmingen vi nettopp brukte: Når skjemaet sendes, forlater vi appen vår, og nettleseren omdirigerer til serverens URL. Vi prøver å unngå alle sideoppdateringer i webapplikasjonen vår, siden vi lager en Single-page application (SPA).

For å sende skjemadataene til serveren uten å tvinge en sideoppdatering, må vi bruke JavaScript-kode. I stedet for å sette en URL i action-egenskapen til et <form>-element, kan du bruke hvilken som helst JavaScript-kode med prefikset javascript: for å utføre en egendefinert handling. Dette betyr også at du må implementere noen oppgaver som tidligere ble gjort automatisk av nettleseren:

  • Hente skjemadataene
  • Konvertere og kode skjemadataene til et passende format
  • Opprette HTTP-forespørselen og sende den til serveren

Oppgave

Erstatt action i registreringsskjemaet med:

<form id="registerForm" action="javascript:register()">

Åpne app.js og legg til en ny funksjon som heter register:

function register() {
  const registerForm = document.getElementById('registerForm');
  const formData = new FormData(registerForm);
  const data = Object.fromEntries(formData);
  const jsonData = JSON.stringify(data);
}

Her henter vi skjemaelementet ved hjelp av getElementById() og bruker FormData-hjelperen for å hente verdiene fra skjemakontroller som et sett med nøkkel/verdi-par. Deretter konverterer vi dataene til et vanlig objekt ved hjelp av Object.fromEntries() og til slutt serialiserer dataene til JSON, et format som ofte brukes for å utveksle data på nettet.

Dataene er nå klare til å sendes til serveren. Lag en ny funksjon som heter createAccount:

async function createAccount(account) {
  try {
    const response = await fetch('//localhost:5000/api/accounts', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: account
    });
    return await response.json();
  } catch (error) {
    return { error: error.message || 'Unknown error' };
  }
}

Hva gjør denne funksjonen? Først, merk nøkkelordet async her. Dette betyr at funksjonen inneholder kode som vil kjøre asynkront. Når det brukes sammen med nøkkelordet await, lar det oss vente på at asynkron kode skal kjøre - som å vente på serverresponsen her - før vi fortsetter.

Her er en rask video om bruk av async/await:

Async og Await for håndtering av løfter

🎥 Klikk på bildet over for en video om async/await.

Vi bruker fetch()-API-et for å sende JSON-data til serveren. Denne metoden tar 2 parametere:

  • URL-en til serveren, så vi setter tilbake //localhost:5000/api/accounts her.
  • Innstillingene for forespørselen. Det er her vi setter metoden til POST og oppgir body for forespørselen. Siden vi sender JSON-data til serveren, må vi også sette Content-Type-headeren til application/json slik at serveren vet hvordan den skal tolke innholdet.

Siden serveren vil svare på forespørselen med JSON, kan vi bruke await response.json() for å analysere JSON-innholdet og returnere det resulterende objektet. Merk at denne metoden er asynkron, så vi bruker nøkkelordet await her før vi returnerer for å sikre at eventuelle feil under analysen også fanges opp.

Legg nå til litt kode i register-funksjonen for å kalle createAccount():

const result = await createAccount(jsonData);

Siden vi bruker nøkkelordet await her, må vi legge til nøkkelordet async før register-funksjonen:

async function register() {

Til slutt, la oss legge til noen logger for å sjekke resultatet. Den endelige funksjonen skal se slik ut:

async function register() {
  const registerForm = document.getElementById('registerForm');
  const formData = new FormData(registerForm);
  const jsonData = JSON.stringify(Object.fromEntries(formData));
  const result = await createAccount(jsonData);

  if (result.error) {
    return console.log('An error occurred:', result.error);
  }

  console.log('Account created!', result);
}

Det var litt langt, men vi kom i mål! Hvis du åpner nettleserens utviklerverktøy og prøver å registrere en ny konto, bør du ikke se noen endring på nettsiden, men en melding vil vises i konsollen som bekrefter at alt fungerer.

Skjermbilde som viser loggmelding i nettleserkonsollen

Tror du dataene sendes til serveren sikkert? Hva om noen klarte å fange opp forespørselen? Du kan lese om HTTPS for å lære mer om sikker datakommunikasjon.

Datavalidering

Hvis du prøver å registrere en ny konto uten å angi et brukernavn først, kan du se at serveren returnerer en feil med statuskode 400 (Bad Request).

Før du sender data til en server, er det en god praksis å validere skjemadataene på forhånd når det er mulig, for å sikre at du sender en gyldig forespørsel. HTML5-skjemaelementer gir innebygd validering ved hjelp av ulike attributter:

  • required: Feltet må fylles ut, ellers kan ikke skjemaet sendes.
  • minlength og maxlength: Definerer minimums- og maksimumsantall tegn i tekstfelt.
  • min og max: Definerer minimums- og maksimumsverdi for et numerisk felt.
  • type: Definerer hvilken type data som forventes, som number, email, file eller andre innebygde typer. Dette attributtet kan også endre den visuelle gjengivelsen av skjemakontrollen.
  • pattern: Lar deg definere et regulært uttrykk-mønster for å teste om de oppgitte dataene er gyldige eller ikke.

Tips: Du kan tilpasse utseendet til skjemakontrollene dine avhengig av om de er gyldige eller ikke, ved å bruke CSS-pseudoklassene :valid og :invalid.

Oppgave

Det er to obligatoriske felt for å opprette en gyldig ny konto: brukernavn og valuta. De andre feltene er valgfrie. Oppdater HTML-skjemaet ved å bruke både required-attributtet og tekst i feltets etikett slik at:

<label for="user">Username (required)</label>
<input id="user" name="user" type="text" required>
...
<label for="currency">Currency (required)</label>
<input id="currency" name="currency" type="text" value="$" required>

Selv om denne spesifikke serverimplementasjonen ikke håndhever spesifikke grenser for maksimal lengde på feltene, er det alltid en god praksis å definere rimelige grenser for tekstinnskriving fra brukeren.

Legg til et maxlength-attributt i tekstfeltene:

<input id="user" name="user" type="text" maxlength="20" required>
...
<input id="currency" name="currency" type="text" value="$" maxlength="5" required>
...
<input id="description" name="description" type="text" maxlength="100">

Nå, hvis du trykker på Registrer og et felt ikke oppfyller en valideringsregel vi har definert, vil du se noe som dette:

Skjermbilde som viser valideringsfeil når man prøver å sende inn skjemaet

Validering som dette, utført før data sendes til serveren, kalles klientsidevalidering. Men merk at det ikke alltid er mulig å utføre alle sjekker uten å sende data. For eksempel kan vi ikke her sjekke om en konto allerede eksisterer med samme brukernavn uten å sende en forespørsel til serveren. Ytterligere validering utført på serveren kalles serversidevalidering.

Vanligvis må begge implementeres, og mens klientsidevalidering forbedrer brukeropplevelsen ved å gi umiddelbar tilbakemelding til brukeren, er serversidevalidering avgjørende for å sikre at brukerdataene du håndterer er pålitelige og sikre.


🚀 Utfordring

Vis en feilmelding i HTML hvis brukeren allerede eksisterer.

Her er et eksempel på hvordan den endelige innloggingssiden kan se ut etter litt styling:

Skjermbilde av innloggingssiden etter å ha lagt til CSS-stiler

Quiz etter forelesning

Quiz etter forelesning

Gjennomgang og selvstudium

Utviklere har blitt svært kreative når det gjelder å bygge skjemaer, spesielt med tanke på valideringsstrategier. Lær om ulike skjemaoppsett ved å se gjennom CodePen; kan du finne noen interessante og inspirerende skjemaer?

Oppgave

Style din bankapp


Ansvarsfraskrivelse:
Dette dokumentet er oversatt ved hjelp av AI-oversettelsestjenesten Co-op Translator. Selv om vi streber etter nøyaktighet, vær oppmerksom på at automatiserte oversettelser kan inneholde feil eller unøyaktigheter. Det originale dokumentet på sitt opprinnelige språk bør anses som den autoritative kilden. For kritisk informasjon anbefales profesjonell menneskelig oversettelse. Vi er ikke ansvarlige for misforståelser eller feiltolkninger som oppstår ved bruk av denne oversettelsen.