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

Hendingshandtering og brukarinteraksjon

I førre kapittel lærte vi å endre nettsida med JavaScript. Men endringane skjedde berre når koden køyrde ved sidelasting. For å skape verkeleg interaktive nettsider treng vi å reagere på handlingane til brukaren – klikk, tastetrykk, muserørsler og skjemainnsending. Dette vert kalla hendingshandtering (event handling).

Hendingssystemet i JavaScript fungerer etter eit enkelt prinsipp: du fortel nettlesaren «når denne hendinga skjer på dette elementet, køyr denne koden». Nettlesaren ventar tolmodig og køyrer koden din berre når hendinga faktisk inntreff. Dette er ein asynkron programmeringsmodell – koden køyrer ikkje i rekkjefølgje frå topp til botn, men som respons på hendingar.

Hending (Event)

Ei hending er ei handling eller hending som skjer i nettlesaren og som JavaScript kan reagere på. Døme er museklikk (click), tastetrykk (keydown), muserørsle (mouseover), siderulling (scroll), lasting av sida (load) og innsending av skjema (submit). Hendingar er grunnlaget for all brukarinteraksjon på webben.

Den tilrådde måten å handtere hendingar på er med addEventListener():

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

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

addEventListener tek to argument:
1. Hendingsnamnet som ein streng (f.eks. "click")
2. Ein funksjon som vert køyrd når hendinga inntreff (vert kalla ein callback-funksjon)

Du kan òg bruke pilfunksjonar:

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

Eller referere til ein namngitt funksjon:

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

knapp.addEventListener("click", handterKlikk);

Vanlege hendingstypar

HendingSkildring
clickMuseklikk på elementet
dblclickDobbeltklikk
mouseoverMusa vert flytta over elementet
mouseoutMusa forlèt elementet
keydownEin tast vert trykt ned
keyupEin tast vert sleppt
inputVerdien i eit inputfelt vert endra
submitEit skjema vert sendt inn
changeEit skjemaelement endrar verdi
scrollSida eller eit element vert rulla
loadSida eller ein ressurs er ferdig lasta

Når ei hending inntreff, sender nettlesaren automatisk eit event-objekt til callback-funksjonen. Dette objektet inneheld nyttig informasjon om hendinga:

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 tastehendingar

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 kjelde-elementet

event.target refererer til det elementet som faktisk utløyste hendinga. Dette er spesielt nyttig når du har mange like element:

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øyrande 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>

Eit av dei viktigaste bruksområda for hendingshandtering er skjemavalidering – å sjekke at brukaren har fylt inn gyldige data før dei vert sende til tenaren.

Hindre standard åtferd

Når eit skjema vert sendt inn, lastar nettlesaren normalt sida på nytt. For å handtere innsendinga med JavaScript må vi stoppe denne åtferda:

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 element som skal reagere på klikk (til dømes ei liste med hundre element), er det ineffektivt å leggje til ein hendingslyttar på kvart einskild element. I staden kan du bruke event delegation – éin lyttar 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);
  }
});

Hendinga boblar opp (event bubbling) frå barneelementet til forelderen. Lyttaren på <ul> fangar opp klikk på alle <li>-element, og event.target fortel oss kva element som vart klikka.

Event delegation har to store fordelar:
1. Yting: Berre éin lyttar i staden for mange
2. Dynamisk innhald: Fungerer òg for element som vert lagde til seinare med JavaScript

✏️Komplett døme: Interaktiv quiz

Her er eit døme som kombinerer hendingshandtering og DOM-manipulering til ein 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";
  }
});

Dømet brukar event delegation på #alternativer-elementet i staden for individuelle lyttarar på kvar knapp. dataset-eigenskapen les data-*-attributt frå HTML, og vi brukar DOM-manipulering for visuell tilbakemelding.

📝Oppgave 5.4.1

Kva metode vert brukt for å lytte etter hendingar i JavaScript?

📝Oppgave 5.4.2

Kva gjer event.preventDefault()?

📝Oppgave 5.4.3

Kva er event.target i denne koden?

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

Når brukaren klikkar på eit <li>-element inne i lista.

📝Oppgave 5.4.4

Kva er fordelen med event delegation?

📝Oppgave 5.4.5

Skriv JavaScript-kode for ein knapp med id="morsknapp". Når knappen vert klikka for første gong, skal teksten i eit <p>-element med id="morsmelding" endrast til "Du er fantastisk!". Ved neste klikk skal teksten endrast til "Og det vet du!". Knappen skal veksle mellom desse to meldingane.

📝Oppgave 5.4.6

Lag ei komplett skjemavalidering med JavaScript. Skjemaet har felta "brukernavn" (minst 3 teikn), "epost" (må innehalde @ og .), og "passord" (minst 8 teikn). Vis feilmeldingar i ein <div> med id="feil". Bruk preventDefault() for å stoppe innsending ved feil.

📝Oppgave 5.4.7

Kva er skilnaden mellom "input"-hendinga og "change"-hendinga på eit tekstfelt?

📝Oppgave 5.4.8

Lag ein interaktiv teljar med JavaScript. Sida har tre knappar: "+1", "-1" og "Nullstill", og eit <span> med id="teller" som viser gjeldande verdi (startar på 0). Teljaren skal ikkje kunne gå under 0. Bruk éin hendingslyttar med event delegation på ein felles forelder-container.

Oppsummering

I dette kapittelet har du lært:

- Hending (event): ei handling i nettlesaren JavaScript kan reagere på.
- addEventListener: koblar ein funksjon til ei hending.
- Hendingstypar: click, keydown, submit m.fl.
- event.target: identifiserer kjelde-elementet.
- preventDefault og skjemavalidering: kontrollerer standard åtferd.

Nøkkelomgrep


OmgrepForklaring
HendingHandling i nettlesaren JavaScript kan reagere på
addEventListenerKoblar funksjon til ei hending
event.targetElementet som utløyste hendinga

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.