Javascript preventDefault • stopPropagation() – »normale« Aktionen verhindern, Events unterbinden

Javascript Event preventDefault setzt die ursprüngliche Aktion des Browsers bei einem HTML-Element außer Kraft (z.B. Sprung zu einer URL beim Klick auf einen Link, Absenden von Formulardaten). Event stopPropagation verhindert, dass ein Event im DOM-Baum nach oben reist und dabei Aktionen auf anderen Elementen triggert.

Javascript prevent default, stop propagation

Default-Aktionen des Events verhindern

Javascript kann Aktionen, die durch ein Event ausgelöst werden, auf zweierlei Weise unterbinden:

  • Event.preventDefault
  • Event.stopPropagation

Einige HTML-Elemente führen Aktionen auch ohne Javascript bei Ereignissen durch. Ein Klick oder Touch auf einen Link führt z.B. zu einer neuen Seite. Ein Formular wird versendet, wenn der Benutzer auf den Button »Absenden« klickt. preventDefault verhindert, dass die vorgesehene Aktion des HTML-Elements durchgeführt wird, z.B., um das Formular mit Javascript zu prüfen, bevor es an die Anwendung auf dem Server geschickt wird.

preventDefault

Typischer Einsatz für evt.preventDefault() sind Formulare, die vor dem Ansenden durch Javascript geprüft werden. Wenn ein Javascript-Event an den submit-Button gebunden ist, muss das normale Verhalten des Buttons unterbunden werden, um das Weiterleiten der Daten an die Anwendung auf dem Server zu blockieren.

<form id="loginForm">
	<input name="user">
	<button type="submit">Absenden</button>
</form>
document
	.getElementById('loginForm')
	.addEventListener('submit', event => {
		event.preventDefault(); // das verhindert Absenden

		// Jetzt ist erst mal Javascript gefordert
		console.log('Formular wurde NICHT abgeschickt');
});
DOM: preventDefault()
Kann das Ereignis unterbinden – canceln. Verhindert jegliche Browser-Aktion für das Ereignis, etwa das Laden einer URL, wenn ein Link geklickt wurde, oder das Absenden der Formulardaten wie in diesem Beispiel.

Event stopPropagation()

Ein Klick-Event entsteht zwar auf dem angeklickten Element (z.B. auf einem Button), aber bevor es dort ankommt, können Listener in der Capturing-Phase reagieren, die entlang des DOM-Baums von window bis zum Ziel ebenfalls auf dieses Event lauschen. Der Browser gibt den Eltern-Elementen die Chance, den Klick auf dem Weg zum Button schon mitzubekommen (Capturing) oder danach darauf zu reagieren (Bubbling).

Der Browser ruft also vorher von oben nach unten:
›Gleich wird hier unten geklickt – will jemand vorher reagieren?‹

und danach von unten nach oben:
›Es wurde geklickt – interessiert das noch jemanden?‹“

stopPropagation() greift nicht beim Entstehen des Events ein, sondern während seiner Reise durch den DOM-Baum. Es wirkt ab dem Punkt, an dem es aufgerufen wird: Alles danach wird nicht mehr ausgeführt.

<div id="parent">
  Parent
  <button class="btn" id="child">Child Button</button>
</div>

Parent

document.getElementById('parent')
  .addEventListener('click', (evt) => {
    console.log('Parent geklickt');
  });

document.getElementById('child')
  .addEventListener('click', () => {
    console.log('Child geklickt');
  });

Dann reist das Event in der Bubbling-Phase wieder nach oben bis zum ROOT. evt.stopPropagation verhindert die Weiterreise des Events. Das ist der Unterschied zwischen preventDefault und return false: return false unterbindet auch die Reise des Events nach oben.

preventDefault vs stopPropagation

preventDefault für das erste Bild verhindert die vorgegebene Aktion des a-Elements, so dass die Seite nicht über den Link verlassen wird. Das Event trifft aber dennoch auf dem Weg zurück nach oben den Parent Node und wird hier erkannt.

<div id="logo1">
   <a id="thelink1" href="formulare-http.html">
      <img src="logo.png" width="" height="" alt="">
   </a>
</div>
<div id="logo2">
   <a id="thelink2" href="formulare-http.html">
      <img src="logo.png" width="" height="" alt="">
   </a>
</div>

stopPropagation im zweiten Kasten verhindert die vorgegebene Aktion des a-Elements nicht. Aber sein Parent Node würde nichts mehr davon mitbekommen.

let link1 = document.querySelector('#link1');
link1.onclick = function (evt) {
   evt.preventDefault();
   console.log('Du gehst hier nicht weg!');
}

thelink1.parentNode.onclick = function ( evt ) {
   console.log ('Das habe ich gehört!');
}
let link2 = document.querySelector('#link2');
link2.onclick = function (evt) {
   evt.stopPropagation();
   console.log('Ich mach trotzdem den Abflug!');
}

thelink2.parentNode.onclick = function ( evt ) {
   console.log ('Davon werde ich nie etwas hören!');
}

In der überwiegenden Zahl von Situationen brauchen wir preventDefault. Man kann aber durchaus beides zusammenbinden:

evt.stopPropagation().preventDefault();
Suchen auf mediaevent.de