EventTarget#

EventTarget.removeEventListener()#

Metoda removeEventListener() usuwa zarejestrowany uchwyt zdarzenia (tzw. uchwyt przez metodę) dla danego celu zdarzenia. Za pomocą trzech argumentów przekazywanych do metody można skonkretyzować główne właściwości usuwanego uchwytu.

Składnia#

Samo wywołanie i poszczególne jego części najlepiej objaśnić na zapisie składniowym:

  1. L
  2. K
  3. T'
  4. T
  5. A
  6. O
  7. Z'
  8. Z
  9. #
eventTarget.removeEventListener(type, callback [, capture = false]);

gdzie poszczególne człony oznaczają:

Algorytm wywołania metody removeEventListener(type, callback, capture) nie jest skomplikowany. Dla lepszego zrozumienia tematu prezentuję go w całości:

  1. Usuń uchwyt zdarzenia z powiązanej listy uchwytów zdarzeń dla obiektu kontekstu, którego typem jest type, funkcją zwrotną jest callback oraz przechwytywaniem jest capture.

Warto podkreślić, że nasłuchy zdarzeń są unikatowe i nie mogą się powtarzać dla tego samego celu zdarzenia. Duplikaty są automatycznie usuwane przez implementację. Nasłuch zdarzenia, który ma być usunięty, jest określany na podstawie trzech argumentów przekazanych do metody removeEventListener() identycznych z tymi, które przekazane zostały do metody Event.addEventListener() w czasie rejestrowania uchwytu. Wystarczy że tylko jeden z nich będzie inny, a będziemy mieli do czynienia z różnymi uchwytami zdarzeń i usunięcie się nie powiedzie.

Najciekawsza sytuacja będzie występować w przypadku drugiego argumentu, czyli funkcji zwrotnej. Dla funkcji anonimowych usunięcie uchwytu zdarzenia za pomocą metody removeEventListener() będzie niemożliwe. Każda funkcja anonimowa jest samodzielnym obiektem (instancją) nawet wtedy, kiedy zawiera te same polecenia (w ciele funkcji). Jedynym sposobem pozbycia się takiego uchwytu będzie całkowite usunięcie obiektu, na którym został on zarejestrowany. W razie konieczności można utworzyć kopię usuwanego obiektu, np. w przypadku węzłów wystarczy klonowanie i zastąpienie oryginału nową kopią, ale trzeba liczyć się z tym, że usunięte zostaną wszystkie pozostałe nasłuchy zdarzeń, które posiadał dany obiekt.

Kiedy inny (lub ten sam) nasłuch zdarzenia zostanie usunięty z aktualnego celu zdarzania w trakcie przetwarzania nasłuchu zdarzenia, to nie będzie to miało wpływu na bieżące operacje, ale będzie respektowane w późniejszej fazie przepływu zdarzeń, np. w fazie bąbelkowania dla tego samego aktualnego celu zdarzenia, w dowolnej fazie dla innych aktualnych celów zdarzenia, lub w trakcie ponownego wysłania zdarzenia. Takie zamrożenie przed przetworzeniem kandydujących nasłuchów zdarzeń w aktualnym celu zdarzenia (dla danej fazy) gwarantuje, że przez przypadek nie doprowadzimy do błędnych zachowań (np. próby usunięcia uchwytu przez samego siebie) lub zapętleń.

Zamiast zawiłych regułek najlepiej przeanalizować jeden przykład teoretyczny. Załóżmy, że mamy do czynienia z następującą ścieżką propagacji jakiegoś zdarzenia:

  1. L
  2. K
  3. T'
  4. T
  5. A
  6. O
  7. Z'
  8. Z
  9. #
         faza przechwytywania             faza celu             faza bąbelkowania

  W1    >     W2     >     W3     >     W     >     W3     >     W2     >     W1
P1 P2 P3      P4                     P5 B1 B2      B3 B4         B5

gdzie:

Oto kilka przykładowych akcji wykonywanych z następujących uchwytów:

Prosty przykład:

  1. L
  2. K
  3. T'
  4. T
  5. A
  6. O
  7. Z'
  8. Z
  9. #
<!DOCTYPE html>
<html>

<head>

	<script>

		// Uruchom po całkowitym załadowaniu dokumentu
		window.onload = function(){

			var button = document.getElementById("press");
			var info = document.getElementById("info");

			var test1 = function(){

				info.innerHTML += "Trzeci uchwyt dla przycisku." + "<br><br>";

			};

			var test2 = function(){

				info.innerHTML += "Uchwyt dla obiektu window." + "<br><br>";

			};

			var test3 = function(){

				// Nie anuluje aktualnie wykonywanych operacji (dla tego samego celu)
				// Efekt usunięcia zostanie zaobserwowany dopiero po ponownym kliknięciu na przycisku
				button.removeEventListener("click", test3, false);

				info.innerHTML += "Uchwyt próbujący skasować samego siebie." + "<br><br>";

			};

			// Uchwyt z referencją do funkcji zwrotnej
			window.addEventListener("click", test2, false);

			// Uchwyt z anonimową funkcją zwrotną
			button.addEventListener("click", function(e){

				info.innerHTML += "Pierwszy uchwyt dla przycisku." + "<br><br>";

				button.removeEventListener("click", test1, false); // usunięcie się nie powiodło (tylko IE9)

				window.removeEventListener("click", test2, false); // usunięcie się powiodło

			}, true);

			// Uchwyt z anonimową funkcją zwrotną
			button.addEventListener("click", function(e){

				info.innerHTML += "Drugi uchwyt dla przycisku." + "<br><br>";

			}, false);

			// Próba usunięcia powyższego uchwytu nie powiedzie się (ze względu na funkcję anonimową)
			button.removeEventListener("click", function(e){

				info.innerHTML += "Drugi uchwyt dla przycisku." + "<br><br>";

			}, false);

			// Uchwyt z referencją do funkcji zwrotnej
			button.addEventListener("click", test1);

			// Uchwyt z referencją do funkcji zwrotnej
			button.addEventListener("click", test3);

		}

	</script>

</head>

<body>

	<p>Kliknij w przycisk by wywołać procedury obsługi wielu uchwytów zdarzeń.</p>
	<input id="press" type="button" value="Kliknij mnie!">

	<p style="color: blue;">Szczegółowe informacje:</p>
	<p id="info"></p>

</body>

</html>

Dokładna analiza powyższego przykładu pozwala zaobserwować i zrozumieć istotne zachowania metody removeEventListener(), szczególnie kiedy próbujemy z procedury obsługi jednego nasłuchu usunąć procedurę obsługi innego nasłuchu (a nawet tego samego nasłuchu), które zarejestrowane zostały dla różnych lub tych samych faz oraz celów. Prawdę mówiąc tylko przeglądarka IE11 zachowuje się w tym aspekcie prawidłowo, pozostałe programy zezwalają na usuwanie kolejnych nasłuchów z poziomu poprzedzających nasłuchów (w ramach tego samego celu i tej samej fazy), co oczywiście jest niezgodne ze specyfikacją. W przypadku analogicznego dodawania nasłuchów metodą Event.addEventListener() błąd został dawno wyeliminowany.

Interfejs Web IDL#

  1. L
  2. K
  3. T'
  4. T
  5. A
  6. O
  7. Z'
  8. Z
  9. #
void removeEventListener(DOMString type, EventListener? callback, optional boolean capture = false);

Specyfikacje i inne materiały#

Pasek społecznościowy

SPIS TREŚCI AKTUALNEJ STRONY

EventTarget (H1) EventTarget.removeEventListener() (H2) Składnia (H3) Interfejs Web IDL (H3) Specyfikacje i inne materiały (H3)