JavaScript: zdarzenia i walidacja formularza

INF.03 · teoria
autor: redakcja · 09.09.2026
Zdarzenia myszy, klawiatury, formularza i strony w języku JavaScript: trzy sposoby podpięcia obsługi, addEventListener, obiekt zdarzenia i preventDefault oraz walidacja formularza po stronie klienta z komunikatem dla użytkownika. Lekcja 11.7 kursu INF.03.
Zda­rze­nie (event) to sygnał, który prze­glą­dar­ka wysyła w chwili, gdy na stro­nie coś się dzieje: użyt­kow­nik klika przy­cisk, wciska kla­wisz, wy­bie­ra po­zy­cję z listy albo wysyła for­mu­larz. Skrypt wczy­ta­ny razem ze stroną prze­cho­dzi raz od góry do dołu i na tym kończy, więc każda re­ak­cja na dzia­ła­nie użyt­kow­ni­ka za­czy­na się od pod­pię­cia funk­cji pod zda­rze­nie. W części pi­sem­nej wra­ca­ją py­ta­nia o nazwy zda­rzeń („które zda­rze­nie za­cho­dzi po na­je­cha­niu kur­so­rem", „które po­zwa­la za­blo­ko­wać wy­sła­nie for­mu­la­rza", „w jakim języku pisze się we­ry­fi­ka­cję for­mu­la­rza po stro­nie prze­glą­dar­ki"). W za­da­niu prak­tycz­nym arkusz każe pod­piąć skrypt pod przy­cisk albo pod za­ła­do­wa­nie strony, pobrać war­tość z pola for­mu­la­rza i spraw­dzić ją przed wy­sła­niem.

Trzy spo­so­by pod­pię­cia ob­słu­gi

Ob­słu­ga zda­rze­nia to funk­cja, którą prze­glą­dar­ka wy­wo­łu­je w chwili, gdy zda­rze­nie zaj­dzie na wska­za­nym ele­men­cie. Pod­piąć ją można na trzy spo­so­by i wszyst­kie trzy stoją w ban­kach pytań.
Pierw­szy to atry­but w znacz­ni­ku HTML. Nazwa atry­bu­tu to nazwa zda­rze­nia z przed­rost­kiem on, a jego war­tość to kod wy­ko­ny­wa­ny po zaj­ściu zda­rze­nia, zwykle wy­wo­ła­nie funk­cji z na­wia­sa­mi.
1
<button onclick="policz()">Policz</button>
Drugi to wła­ści­wość ele­men­tu. Ele­ment po­bie­ra się metodą getElementById, opi­sa­ną w lekcji o modelu DOM, a potem przy­pi­su­je mu się funk­cję.
1
2
const przycisk = document.getElementById("licz");
przycisk.onclick = policz;
Po prawej stro­nie stoi sama nazwa funk­cji, bez na­wia­sów. Na­wia­sy wy­wo­ła­ły­by ją od razu przy wczy­ty­wa­niu strony, a pod zda­rze­nie tra­fi­ła­by wtedy zwró­co­na przez nią war­tość.
Trzeci to metoda addEventListener (DODAJ SŁUCHACZA ZDARZENIA). Bierze dwa ar­gu­men­ty: nazwę zda­rze­nia jako napis i funk­cję do wy­wo­ła­nia.
1
2
const przycisk = document.getElementById("licz");
przycisk.addEventListener("click", policz);
Sposób
Zapis
Ogra­ni­cze­nie
atry­but znacz­ni­ka
<button onclick="policz()">
kod skryp­tu miesza się z tre­ścią strony
wła­ści­wość ele­men­tu
przycisk.onclick = policz;
tylko jedna funk­cja na zda­rze­nie
addEventListener
przycisk.addEventListener("click", policz);
wymaga wcze­śniej­sze­go po­bra­nia ele­men­tu
Trzeci sposób jest naj­lep­szy z dwóch po­wo­dów. Pod jedno zda­rze­nie jed­ne­go ele­men­tu wolno pod­piąć do­wol­nie wiele funk­cji i wy­ko­na­ją się one po kolei, a ko­lej­ne przy­pi­sa­nie do onclick kasuje po­przed­nie i zo­sta­wia wy­łącz­nie ostat­nią funk­cję. Do tego cały kod zo­sta­je w pliku .js, więc znacz­nik w HTML nie wie nic o skryp­cie. Metoda removeEventListener z tą samą nazwą zda­rze­nia i tą samą funk­cją odpina ob­słu­gę z po­wro­tem.
Pu­łap­ka: w addEventListener nazwa zda­rze­nia jest na­pi­sem BEZ przed­rost­ka on, czyli "click", a nie "onclick". Przed­ro­stek ma tylko atry­but w znacz­ni­ku i wła­ści­wość ele­men­tu.

Zda­rze­nia myszy i kla­wia­tu­ry

Zda­rze­nie myszy to zda­rze­nie wy­wo­ła­ne ruchem kur­so­ra albo na­ci­śnię­ciem przy­ci­sku myszy, a zda­rze­nie kla­wia­tu­ry na­ci­śnię­ciem kla­wi­sza. To one wra­ca­ją w py­ta­niach pi­sem­nych naj­czę­ściej, bo wy­star­czy znać nazwę.
Zda­rze­nie
Atry­but
Kiedy za­cho­dzi
click
onclick
po­je­dyn­cze klik­nię­cie ele­men­tu
dblclick
ondblclick
dwu­krot­ne klik­nię­cie ele­men­tu
mousedown
onmousedown
wci­śnię­cie przy­ci­sku myszy
mouseup
onmouseup
zwol­nie­nie przy­ci­sku myszy
mouseover
onmouseover
kursor wcho­dzi na ele­ment
mouseout
onmouseout
kursor opusz­cza ele­ment
keydown
onkeydown
kla­wisz kla­wia­tu­ry został na­ci­śnię­ty
keyup
onkeyup
kla­wisz kla­wia­tu­ry został zwol­nio­ny
keypress
onkeypress
na­ci­śnię­cie kla­wi­sza zna­ko­we­go, zapis wy­co­fa­ny ze stan­dar­du
Para mouseover i mouseout ob­słu­gu­je pod­świe­tla­nie: pierw­sze za­cho­dzi w chwili wje­cha­nia kur­so­ra na ele­ment, drugie po jego zje­cha­niu.
1
2
3
4
5
6
7
const promocja = document.getElementById("promocja");
promocja.addEventListener("mouseover", function () {
promocja.style.backgroundColor = "Tomato";
});
promocja.addEventListener("mouseout", function () {
promocja.style.backgroundColor = "white";
});
Wynik: tło ele­men­tu o id="promocja" robi się czer­wo­ne pod kur­so­rem i wraca do bia­łe­go, gdy kursor go opuści.
Licz­nik wpi­sa­nych znaków pod­pi­na się pod keyup, a nie pod keydown. Zda­rze­nie keydown za­cho­dzi PRZED wpi­sa­niem znaku do pola, więc od­czy­ta­na w nim war­tość jest jesz­cze o jeden znak krót­sza.
1
2
3
4
5
const uwagi = document.getElementById("uwagi");
const licznik = document.getElementById("licznik");
uwagi.addEventListener("keyup", function () {
licznik.innerHTML = uwagi.value.length;
});
Wynik: po każdym na­ci­śnię­ciu kla­wi­sza w ele­men­cie o id="licznik" po­ja­wia się ak­tu­al­na liczba znaków wpi­sa­nych w polu.

Zda­rze­nia for­mu­la­rza i strony

Zda­rze­nie for­mu­la­rza to zda­rze­nie za­cho­dzą­ce na kon­tro­l­ce albo na całym for­mu­la­rzu pod­czas jego wy­peł­nia­nia i wy­sy­ła­nia, a zda­rze­nie strony do­ty­czy całego do­ku­men­tu i jego wczy­ty­wa­nia.
Zda­rze­nie
Atry­but
Kiedy za­cho­dzi
Na czym
submit
onsubmit
próba wy­sła­nia for­mu­la­rza
<form>
reset
onreset
na­ci­śnię­cie przy­ci­sku ka­su­ją­ce­go
<form>
change
onchange
zmiana war­to­ści za­twier­dzo­na wyj­ściem z pola
kon­tro­l­ka
input
oninput
każda zmiana war­to­ści, znak po znaku
kon­tro­l­ka
focus
onfocus
kursor wcho­dzi do pola
kon­tro­l­ka
blur
onblur
kursor opusz­cza pole
kon­tro­l­ka
load
onload
strona razem z ob­ra­za­mi jest wczy­ta­na
<body>
DOMContentLoaded
brak atry­bu­tu
kod HTML jest prze­two­rzo­ny, obrazy jesz­cze nie
document
Zda­rze­nie submit za­cho­dzi na znacz­ni­ku <form>, nie na przy­ci­sku: przy­cisk typu submit tylko je wy­zwa­la. Ob­słu­gę wy­sył­ki pod­pi­na się więc do for­mu­la­rza, a nie do przy­ci­sku. Przy liście roz­wi­ja­nej change za­cho­dzi zaraz po wy­bra­niu innej po­zy­cji, ale w polu tek­sto­wym do­pie­ro po wyj­ściu z niego, więc do spraw­dza­nia w trak­cie pi­sa­nia nadaje się input albo keyup.
Skrypt umiesz­czo­ny w znacz­ni­ku <head> wy­ko­nu­je się, zanim prze­glą­dar­ka zbu­du­je resztę strony, więc getElementById zwraca w nim null i pod­pię­cie ob­słu­gi się nie udaje. Wyj­ścia są dwa: do­łą­cze­nie pliku za­pi­sem <script src="skrypt.js"></script> przed za­mknię­ciem </body>, tak jak robią to ar­ku­sze CKE, albo owi­nię­cie kodu w ob­słu­gę zda­rze­nia DOMContentLoaded.
1
2
3
4
document.addEventListener("DOMContentLoaded", function () {
const przycisk = document.getElementById("licz");
przycisk.addEventListener("click", policz);
});
Wynik: ob­słu­ga klik­nię­cia zo­sta­je pod­pię­ta do­pie­ro wtedy, gdy przy­cisk o id="licz" ist­nie­je już w do­ku­men­cie. Zda­rze­nie load czeka do­dat­ko­wo na obrazy i ar­ku­sze stylów, więc uru­cha­mia kod póź­niej niż DOMContentLoaded.

Obiekt zda­rze­nia i do­myśl­ne dzia­ła­nie

Obiekt zda­rze­nia to zestaw danych o tym, co się wła­śnie stało, po­da­wa­ny funk­cji ob­słu­gu­ją­cej jako pierw­szy ar­gu­ment. Zwy­cza­jo­wo nazywa się go event albo krócej e.
Zapis
Co niesie
event.type
nazwa zda­rze­nia, na przy­kład click
event.target
ele­ment, na którym zda­rze­nie zaszło
event.key
znak na­ci­śnię­te­go kla­wi­sza, w zda­rze­niach kla­wia­tu­ry
event.preventDefault()
blo­ku­je do­myśl­ne dzia­ła­nie prze­glą­dar­ki
Do­myśl­ne dzia­ła­nie to re­ak­cja, którą prze­glą­dar­ka wy­ko­nu­je sama, bez skryp­tu: klik­nię­ty od­no­śnik prze­no­si na inną stronę, a przy­cisk typu submit wysyła for­mu­larz i prze­ła­do­wu­je stronę. Metoda preventDefault (ZAPOBIEGNIJ DOMYŚLNEMU) tę re­ak­cję za­trzy­mu­je, a reszta funk­cji wy­ko­nu­je się nor­mal­nie.
1
2
3
4
5
const formularz = document.getElementById("zamowienie");
formularz.addEventListener("submit", function (event) {
event.preventDefault();
document.getElementById("komunikat").innerHTML = "Sprawdź ilość";
});
Wynik: na­ci­śnię­cie przy­ci­sku wy­sy­ła­ją­ce­go nie prze­ła­do­wu­je już strony, a w ele­men­cie o id="komunikat" po­ja­wia się napis.
W za­pi­sie atry­bu­tem tę samą rolę pełni słowo return (ZWRÓĆ). Zapis onsubmit="return sprawdz()" wysyła for­mu­larz tylko wtedy, gdy funk­cja sprawdz zwróci true, a zwró­co­ne false za­trzy­mu­je wy­sył­kę do­kład­nie tak samo jak preventDefault. Samo onsubmit="sprawdz()" bez słowa return nie za­trzy­ma ni­cze­go, choćby funk­cja zwra­ca­ła false.

Wa­li­da­cja for­mu­la­rza po stro­nie klien­ta

Wa­li­da­cja to spraw­dze­nie, czy wpro­wa­dzo­ne dane speł­nia­ją okre­ślo­ne reguły. Po stro­nie klien­ta robi ją prze­glą­dar­ka, zanim co­kol­wiek po­je­dzie na serwer, więc użyt­kow­nik do­sta­je ko­mu­ni­kat od razu, bez prze­ła­do­wa­nia strony.
Pierw­szą war­stwę daje sam HTML5, bez jednej linii skryp­tu: required nie wy­pusz­cza pu­ste­go pola, type="number" z atry­bu­ta­mi min i max pil­nu­je za­kre­su, pattern spraw­dza wzo­rzec, a novalidate w znacz­ni­ku <form> wy­łą­cza całe spraw­dza­nie. Atry­bu­ty te opi­su­je lekcja o for­mu­la­rzach HTML. Reguły HTML5 spraw­dza­ne są PRZED zda­rze­niem submit, więc gdy pole z required zo­sta­nie puste, funk­cja pod­pię­ta pod submit w ogóle się nie uru­cho­mi.
JavaScript do­kła­da to, czego atry­bu­ty nie po­tra­fią: po­rów­na­nie dwóch pól ze sobą, własną treść ko­mu­ni­ka­tu i własne miej­sce, w którym on się po­ka­zu­je. Sche­mat jest zawsze ten sam: po­bierz war­tość, sprawdź wa­ru­nek, przy błę­dzie pokaż ko­mu­ni­kat i zwróć false.
1
2
3
4
5
<form id="zamowienie" action="zamow.php" method="post" onsubmit="return sprawdz()">
<input type="text" id="imie" name="imie">
<input type="text" id="ilosc" name="ilosc">
<input type="submit" value="Zamów">
</form>
1
2
3
4
5
6
7
8
9
10
11
12
13
function sprawdz() {
const imie = document.getElementById("imie").value.trim();
const ilosc = Number(document.getElementById("ilosc").value);
if (imie === "") {
alert("Podaj imię i nazwisko");
return false;
}
if (isNaN(ilosc) || ilosc < 1 || ilosc > 10) {
alert("Ilość musi być liczbą od 1 do 10");
return false;
}
return true;
}
Wynik: puste imię albo ilość spoza za­kre­su od 1 do 10 za­trzy­mu­je for­mu­larz i po­ka­zu­je okno z ko­mu­ni­ka­tem, a po­praw­ne dane jadą metodą POST do pliku zamow.php.
Trzy ka­wał­ki tego kodu warto ro­ze­brać. Wła­ści­wość value (war­tość) oddaje zawsze NAPIS, nawet w polu type="number", więc po­rów­na­nie licz­bo­we wymaga kon­wer­sji funk­cją Number albo parseInt. Metoda trim (PRZYTNIJ) usuwa spacje z obu końców napisu, bo bez niej pole wy­peł­nio­ne samymi spa­cja­mi prze­cho­dzi jako nie­pu­ste. Funk­cja isNaN (NIE JEST LICZBĄ) łapie wpi­sa­ny tekst, bo Number("dwa") daje NaN, a każde po­rów­na­nie z NaN jest fał­szy­we, więc sam wa­ru­nek za­kre­su takiej war­to­ści by nie od­rzu­cił.
Ko­mu­ni­kat nie musi być oknem alert. Wsta­wio­ny do pu­ste­go aka­pi­tu obok pola zo­sta­je na ekra­nie i nie blo­ku­je strony.
1
2
3
const komunikat = document.getElementById("komunikat");
komunikat.innerHTML = "Ilość musi być liczbą od 1 do 10";
komunikat.style.color = "Maroon";
Wynik: bor­do­wy napis w ele­men­cie o id="komunikat". Wła­ści­wość innerHTML wsta­wia kod HTML, więc do tekstu po­cho­dzą­ce­go od użyt­kow­ni­ka bez­piecz­niej­sza jest wła­ści­wość textContent, która trak­tu­je wszyst­ko jako zwykły napis.
Pu­łap­ka: wa­li­da­cja u klien­ta to wygoda dla użyt­kow­ni­ka, a nie za­bez­pie­cze­nie. JavaScript da się wy­łą­czyć, a żą­da­nie wysłać z po­mi­nię­ciem strony, więc te same reguły musi po­wtó­rzyć skrypt na ser­we­rze, opi­sa­ny w lekcji o for­mu­la­rzach w PHP.

Na eg­za­mi­nie

Py­ta­nia pi­sem­ne o zda­rze­nia spro­wa­dza­ją się naj­czę­ściej do jednej nazwy. Re­ak­cją na po­je­dyn­cze klik­nię­cie do­wol­ne­go ele­men­tu strony jest onclick, a nie onload ani onkeydown. Zda­rze­niem wy­zwa­la­nym, gdy kursor myszy znaj­dzie się nad ele­men­tem, jest onmouseover, na­to­miast onmouseout za­cho­dzi po jego opusz­cze­niu, a onmousedown i onmouseup do­ty­czą przy­ci­sku myszy, nie ruchu kur­so­ra. Zda­rze­nie onkeydown za­cho­dzi w chwili na­ci­śnię­cia kla­wi­sza KLAWIATURY, a onkeyup po jego zwol­nie­niu, więc funk­cja, która ma dzia­łać po każdym wpi­sa­nym do pola znaku, pod­pi­na się pod jedno z nich. Kodem wy­ko­ny­wa­nym w chwili wy­sy­ła­nia for­mu­la­rza, z moż­li­wo­ścią za­blo­ko­wa­nia albo prze­pusz­cze­nia wy­sył­ki, ste­ru­je onsubmit, nie onclick ani onchange.
Osobna grupa pytań do­ty­czy po­dzia­łu pracy między prze­glą­dar­kę i serwer. We­ry­fi­ka­cję kom­plet­no­ści for­mu­la­rza dzia­ła­ją­cą po stro­nie prze­glą­dar­ki pisze się w języku JavaScript, a nie w PHP, CSS czy Ruby. Gdy za­da­nie mówi o spraw­dza­niu danych w czasie rze­czy­wi­stym i za­pi­sa­niu ich potem do bazy, naj­prost­szy po­dział to wa­li­da­cja w języku JavaScript i prze­sła­nie danych skryp­tem PHP. Zdarza się też ramka z kodem i py­ta­nie o efekt klik­nię­cia przy­ci­sku: trzeba wtedy prze­śle­dzić, który ele­ment po­bie­ra getElementById i co skrypt mu zmie­nia, innerHTML czy style.
W za­da­niu prak­tycz­nym po­le­ce­nie brzmi zwykle „przy­cisk uru­cha­mia­ją­cy skrypt" albo „skrypt wy­ko­ny­wa­ny po za­ła­do­wa­niu strony". Pierw­sze to <button onclick="nazwa()"> lub addEventListener po po­bra­niu przy­ci­sku, drugie to <body onload="nazwa()"> albo plik do­łą­czo­ny przed </body>. Iden­ty­fi­ka­to­ry muszą zga­dzać się co do znaku: id="ilosc" w znacz­ni­ku i getElementById("ilosc") w kodzie, przy czym name służy wy­sył­ce na serwer, a id wy­szu­ki­wa­niu w skryp­cie. Ar­ku­sze piszą skryp­ty w star­szym stylu, z var za­miast let, ob­słu­gą w atry­bu­cie onclick i wy­pi­sy­wa­niem przez document.write. Taki zapis działa i od­two­rze­nie go nie jest błędem, choć w kodzie pi­sa­nym od zera lepsze są let, const i addEventListener, a document.write uru­cho­mio­ny po wczy­ta­niu strony kasuje jej do­tych­cza­so­wą treść. Oce­nia­ne re­zul­ta­ty to „skrypt" i „dzia­ła­nie wi­try­ny", więc eg­za­mi­na­tor klika po go­to­wej stro­nie: skrypt, który nie re­agu­je na klik­nię­cie, punktu nie do­sta­nie, choćby w pliku wy­glą­dał po­praw­nie.

Ściąga

Zapis
Znaczy
<button onclick="licz()">
ob­słu­ga w atry­bu­cie znacz­ni­ka, wy­wo­ła­nie z na­wia­sa­mi
przycisk.onclick = licz;
ob­słu­ga we wła­ści­wo­ści, bez na­wia­sów, tylko jedna funk­cja
el.addEventListener("click", licz);
ob­słu­ga do­pi­sa­na, nazwa zda­rze­nia bez on, wiele funk­cji
el.removeEventListener("click", licz);
od­pię­cie wcze­śniej do­da­nej ob­słu­gi
onclick, ondblclick
po­je­dyn­cze i dwu­krot­ne klik­nię­cie ele­men­tu
onmouseover, onmouseout
kursor wcho­dzi na ele­ment i go opusz­cza
onmousedown, onmouseup
wci­śnię­cie i zwol­nie­nie przy­ci­sku myszy
onkeydown, onkeyup
kla­wisz kla­wia­tu­ry na­ci­śnię­ty i zwol­nio­ny
onsubmit
próba wy­sła­nia for­mu­la­rza, za­cho­dzi na znacz­ni­ku <form>
onchange, oninput
zmiana war­to­ści po wyj­ściu z pola i znak po znaku
onfocus, onblur
wej­ście kur­so­ra do pola i wyj­ście z niego
onload
strona z ob­ra­za­mi wczy­ta­na, atry­but znacz­ni­ka <body>
DOMContentLoaded
kod HTML prze­two­rzo­ny, obrazy jesz­cze nie
event.target
ele­ment, na którym zda­rze­nie zaszło
event.preventDefault()
blo­ku­je do­myśl­ne dzia­ła­nie, na przy­kład wy­sył­kę for­mu­la­rza
onsubmit="return sprawdz()"
wysyła for­mu­larz tylko przy zwró­co­nym true
pole.value
war­tość kon­tro­l­ki, zawsze napis
Number(pole.value)
kon­wer­sja war­to­ści pola na liczbę przed po­rów­na­niem
isNaN(x)
prawda, gdy x nie jest liczbą
Pobierz ściągę PDF
ZAWODNIK
egzamin zawodowy INF.02 · INF.03 · INF.04
Serwer Discord
Egzaminy zawodowe IT/Matury/Studia
@yastor
© 2026 Zawodnik · by Yastor
Arkusze i zasady oceniania pochodzą z CKE. Serwis nie jest powiązany z Centralną Komisją Egzaminacyjną.