Tilbake
5.4
Hendelseshåndtering og brukerinteraksjon

5.4 Hendelseshåndtering og brukerinteraksjon

Lær å gjøre nettsider interaktive med klikk, tastatur og skjemahendelser.

60 min
8 oppgaver
HendelseaddEventListenerEvent-objektEvent delegation
Du leser den tradisjonelle versjonen
Din fremgang i kapitlet
0 / 8 oppgaver

Hendelseshåndtering og brukerinteraksjon

I forrige kapittel lærte vi å endre nettsiden med JavaScript. Men endringene skjedde bare når koden kjørte ved sidelasting. For å skape virkelig interaktive nettsider trenger vi å reagere på brukerens handlinger – klikk, tastettrykk, musebevegelser og skjemainnsending. Dette kalles hendelseshåndtering (event handling).

Hendelsessystemet i JavaScript fungerer etter et enkelt prinsipp: du forteller nettleseren «når denne hendelsen skjer på dette elementet, kjør denne koden». Nettleseren venter tålmodig og kjører koden din bare når hendelsen faktisk inntreffer. Dette er en asynkron programmeringsmodell – koden kjører ikke i rekkefølge fra topp til bunn, men som respons på hendelser.

Hendelse (Event)

En hendelse er en handling eller forekomst som skjer i nettleseren og som JavaScript kan reagere på. Eksempler er museklikk (click), tastettrykk (keydown), musebevegelse (mouseover), siderulling (scroll), lasting av siden (load) og innsending av skjema (submit). Hendelser er grunnlaget for all brukerinteraksjon på webben.

Den anbefalte måten å håndtere hendelser på er med addEventListener():

const knapp = document.querySelector("#minKnapp");

knapp.addEventListener("click", function () {
  console.log("Knappen ble klikket!");
});

addEventListener tar to argumenter:
1. Hendelsesnavnet som en streng (f.eks. "click")
2. En funksjon som kjøres når hendelsen inntreffer (kalles en callback-funksjon)

Du kan også bruke pilfunksjoner:

knapp.addEventListener("click", () => {
  console.log("Klikk registrert!");
});

Eller referere til en navngitt funksjon:

function handterKlikk() {
  console.log("Funksjon ble kalt!");
}

knapp.addEventListener("click", handterKlikk);

Vanlige hendelsestyper

HendelseBeskrivelse
clickMuseklikk på elementet
dblclickDobbeltklikk
mouseoverMusen beveges over elementet
mouseoutMusen forlater elementet
keydownEn tast trykkes ned
keyupEn tast slippes
inputVerdien i et inputfelt endres
submitEt skjema sendes inn
changeEt skjemaelement endrer verdi
scrollSiden eller et element rulles
loadSiden eller en ressurs er ferdig lastet

Når en hendelse inntreffer, sender nettleseren automatisk et event-objekt til callback-funksjonen. Dette objektet inneholder nyttig informasjon om hendelsen:

const knapp = document.querySelector("#minKnapp");

knapp.addEventListener("click", function (event) {
  console.log("Type:", event.type);          // "click"
  console.log("Mål:", event.target);          // Elementet som ble klikket
  console.log("X-posisjon:", event.clientX);  // Musens x-koordinat
  console.log("Y-posisjon:", event.clientY);  // Musens y-koordinat
});

Event-objektet for tastehendelser

document.addEventListener("keydown", function (event) {
  console.log("Tast:", event.key);         // F.eks. "Enter", "a", "Escape"
  console.log("Kode:", event.code);        // F.eks. "Enter", "KeyA", "Escape"
  console.log("Shift holdt:", event.shiftKey);  // true/false
  console.log("Ctrl holdt:", event.ctrlKey);    // true/false
});

event.target – identifiser kilde-elementet

event.target refererer til det elementet som faktisk utløste hendelsen. Dette er spesielt nyttig når du har mange like elementer:

const knapper = document.querySelectorAll(".farge-knapp");

knapper.forEach(knapp => {
  knapp.addEventListener("click", function (event) {
    const valgtFarge = event.target.dataset.farge;
    document.body.style.backgroundColor = valgtFarge;
  });
});

Med tilhørende HTML:

<button class="farge-knapp" data-farge="lightblue">Blå</button>
<button class="farge-knapp" data-farge="lightgreen">Grønn</button>
<button class="farge-knapp" data-farge="lightyellow">Gul</button>

En av de viktigste bruksområdene for hendelseshåndtering er skjemavalidering – å sjekke at brukeren har fylt inn gyldige data før de sendes til serveren.

Forhindre standard oppførsel

Når et skjema sendes inn, laster nettleseren normalt siden på nytt. For å håndtere innsendingen med JavaScript må vi stoppe denne oppførselen:

const skjema = document.querySelector("#registrering");

skjema.addEventListener("submit", function (event) {
  event.preventDefault();  // Stopp sidelasting!

  // Hent verdier fra skjemaet
  const navn = document.querySelector("#navn").value;
  const epost = document.querySelector("#epost").value;

  console.log("Navn:", navn);
  console.log("E-post:", epost);
});

Komplett skjemavalidering

<form id="pamelding">
  <label>Navn: <input type="text" id="navn"></label>
  <label>E-post: <input type="email" id="epost"></label>
  <label>Alder: <input type="number" id="alder"></label>
  <button type="submit">Send inn</button>
  <div id="feilmeldinger"></div>
</form>

const skjema = document.querySelector("#pamelding");

skjema.addEventListener("submit", function (event) {
  event.preventDefault();

  const navn = document.querySelector("#navn").value.trim();
  const epost = document.querySelector("#epost").value.trim();
  const alder = Number(document.querySelector("#alder").value);
  const feilDiv = document.querySelector("#feilmeldinger");
  const feil = [];

  // Valider navn
  if (navn === "") {
    feil.push("Navn er obligatorisk.");
  } else if (navn.length < 2) {
    feil.push("Navnet må ha minst 2 tegn.");
  }

  // Valider e-post (enkel sjekk)
  if (!epost.includes("@") || !epost.includes(".")) {
    feil.push("Ugyldig e-postadresse.");
  }

  // Valider alder
  if (isNaN(alder) || alder < 13 || alder > 120) {
    feil.push("Alder må være mellom 13 og 120.");
  }

  // Vis resultat
  if (feil.length > 0) {
    feilDiv.innerHTML = feil.map(f => "<p style='color:red'>" + f + "</p>").join("");
  } else {
    feilDiv.innerHTML = "<p style='color:green'>Påmelding mottatt!</p>";
  }
});

Når du har mange elementer som skal reagere på klikk (for eksempel en liste med hundre elementer), er det ineffektivt å legge til en hendelseslytter på hvert enkelt element. I stedet kan du bruke event delegation – én lytter på forelder-elementet:

// I stedet for dette (ineffektivt):
document.querySelectorAll("li").forEach(li => {
  li.addEventListener("click", function () {
    console.log(this.textContent);
  });
});

// Bruk event delegation (effektivt):
document.querySelector("ul").addEventListener("click", function (event) {
  if (event.target.tagName === "LI") {
    console.log(event.target.textContent);
  }
});

Hendelsen bobler opp (event bubbling) fra barneelementet til forelderen. Lytteren på <ul> fanger opp klikk på alle <li>-elementer, og event.target forteller oss hvilket element som ble klikket.

Event delegation har to store fordeler:
1. Ytelse: Bare én lytter i stedet for mange
2. Dynamisk innhold: Fungerer også for elementer som legges til senere med JavaScript

✏️Komplett eksempel: Interaktiv quiz

Her er et eksempel som kombinerer hendelseshåndtering og DOM-manipulering til en liten quiz:

<div id="quiz">
  <h2>Quiz: JavaScript</h2>
  <p id="sporsmal">Hva brukes JavaScript til?</p>
  <div id="alternativer">
    <button class="alt" data-korrekt="false">Å strukturere nettsider</button>
    <button class="alt" data-korrekt="true">Å gjøre nettsider interaktive</button>
    <button class="alt" data-korrekt="false">Å style nettsider</button>
  </div>
  <p id="resultat"></p>
</div>

const alternativer = document.querySelector("#alternativer");
const resultat = document.querySelector("#resultat");

alternativer.addEventListener("click", function (event) {
  // Sjekk at et alternativ-knapp ble klikket
  if (!event.target.classList.contains("alt")) {
    return;
  }

  const erKorrekt = event.target.dataset.korrekt === "true";

  // Deaktiver alle knapper
  document.querySelectorAll(".alt").forEach(knapp => {
    knapp.disabled = true;
    if (knapp.dataset.korrekt === "true") {
      knapp.style.backgroundColor = "lightgreen";
    }
  });

  // Vis tilbakemelding
  if (erKorrekt) {
    resultat.textContent = "Riktig! JavaScript gjør nettsider interaktive.";
    resultat.style.color = "green";
    event.target.style.backgroundColor = "lightgreen";
  } else {
    resultat.textContent = "Feil! Prøv igjen neste gang.";
    resultat.style.color = "red";
    event.target.style.backgroundColor = "lightcoral";
  }
});

Eksempelet bruker event delegation på #alternativer-elementet i stedet for individuelle lyttere på hver knapp. dataset-egenskapen leser data-*-attributter fra HTML, og vi bruker DOM-manipulering for visuell tilbakemelding.

📝Oppgave 5.4.1

Hvilken metode brukes for å lytte etter hendelser i JavaScript?

📝Oppgave 5.4.2

Hva gjør event.preventDefault()?

📝Oppgave 5.4.3

Hva er event.target i denne koden?

document.querySelector("ul").addEventListener("click", function(event) {
  console.log(event.target);
});

Når brukeren klikker på et <li>-element inne i listen.

📝Oppgave 5.4.4

Hva er fordelen med event delegation?

📝Oppgave 5.4.5

Skriv JavaScript-kode for en knapp med id="morsknapp". Når knappen klikkes for første gang, skal teksten i et <p>-element med id="morsmelding" endres til "Du er fantastisk!". Ved neste klikk skal teksten endres til "Og det vet du!". Knappen skal veksle mellom disse to meldingene.

📝Oppgave 5.4.6

Lag en komplett skjemavalidering med JavaScript. Skjemaet har feltene "brukernavn" (minst 3 tegn), "epost" (må inneholde @ og .), og "passord" (minst 8 tegn). Vis feilmeldinger i et <div> med id="feil". Bruk preventDefault() for å stoppe innsending ved feil.

📝Oppgave 5.4.7

Hva er forskjellen mellom "input"-hendelsen og "change"-hendelsen på et tekstfelt?

📝Oppgave 5.4.8

Lag en interaktiv teller med JavaScript. Siden har tre knapper: "+1", "-1" og "Nullstill", og et <span> med id="teller" som viser gjeldende verdi (starter på 0). Telleren skal ikke kunne gå under 0. Bruk én hendelseslytter med event delegation på en felles forelder-container.

Oppsummering

I dette kapittelet har du lært:

- Hendelse (event): en handling i nettleseren JavaScript kan reagere på.
- addEventListener: kobler en funksjon til en hendelse.
- Hendelsestyper: click, keydown, submit m.fl.
- event.target: identifiserer kilde-elementet.
- preventDefault og skjemavalidering: kontrollerer standard oppførsel.

Noekkelbegreper


BegrepForklaring
HendelseHandling i nettleseren JavaScript kan reagere på
addEventListenerKobler funksjon til en hendelse
event.targetElementet som utløste hendelsen

Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.