Rolf B: JavaScript greift auf bereits entfernte DOM-Elemente zu?

Beitrag lesen

problematische Seite

Hallo borisbaer,

Stattdessen hatte ich ihn zwischen .then und .catch. 😯

Da gehört er ja nun gar nicht hin. Hinter fetch folgt eine Folge von .then und .catch Aufrufen, die alle auf Promises aufgerufen werden, die aus dem fetch-Aufruf entstehen. Auch nicht so einfach zu kapieren, das gebe ich zu.

Also handelt es sich bei diesen lokalen Variablen um eine ganz spezifische Zuordnung zu ganz bestimmten Elementen im DOM?

Ja. Du ermittelst sie aus dem DOM, und dann bleiben sie in der Closure stehen, die an den Eventhandlern hängt. Und weil Du die Eventhandler nicht beseitigst, leben sie "ewig", bzw. bis zum Seitenrefresh.

Heißt das, dass bei jedem Aufruf der Mutterfunktion (changePage) eine neue Kindfunktion(newPage) erstellt wird?

Genau das wollte ich sagen, ja. Der dahinterliegende Quellcode ist der gleiche, aber es ist jedesmal ein neues Funktionsobjekt, mit einer eigenen Closure um die lokalen Daten des changePage-Aufrufs.

Kapiert. Jetzt habe ich nur das Problem, dass eigentlich beim Umblättern mit den Pfeil-Tasten der Fokus auf den jeweiligen Pfeil-Button gelegt werden soll.

Das sollte kein Problem sein; Du hast im keydown-Handler ein arrowLeft.focus(); stehen, DAS kannst Du machen, wenn die Pfeile unverändert im DOM bleiben. Du kannst natürlich auch den beiden Buttons eine ID geben und sie nach Bedarf mit getElementById heraussuchen.

Leider habe ich keine Ahnung, was genau du damit meinst bzw. wie ich das umsetzen sollte. 🙁 Sie dürfen keine Kontextinformationen brauchen … hmm.

Du solltest die newPage-Funktion nur einmal erzeugen, d.h. nicht innerhalb von changePage, sondern separat.

Innerhalb von newPage nutzt Du im Moment die page-Variable, um die vorhandenen Karten zu ermitteln. Verwende eine lokale Variable page (oder maps) und initialisiere sie zu Beginn von newPage mit

let page = document.querySelectorAll( '.maps .page' );

und die erste Abhängigkeit zum changePage-Kontext ist weg. Die executed Variable ist eine andere Sache, deren Zweck verstehe ich noch nicht. Damit steuerst Du offenbar das Zuweisen der Klasse 'on', das beim ERSTEN Mal - also beim ersten newPage Aufruf für ein Kartenset - nicht passieren soll. Mir scheint, das ist genau den newPage Aufruf, der in changePage direkt passiert, die übrigen kommen aus den Eventlistenern. Eventuell kannst Du newPage einen zweiten Parameter mitgeben, der beim newPage-Aufruf in Zeile 127 (also newpage(pageNumber) false ist und beim newPage-Aufruf aus den Eventhandlern true, und damit das Zuweisen der Klasse steuern.

Ich habe mir jetzt nicht alles angeschaut und kann daher nicht sagen, ob sich die Animation eleganter steuern lässt.

Die letzte Amtshandlung von newPage ist das Setzen der globalen Variablen pageNumber. Diese globale Variable muss weg, die pageNumber muss sich aus dem DOM ermitteln. Deswegen habe ich Dir aria-selected empfohlen. Die Eventhandler können, statt pageNumber zu nutzen, die Pages durchgehen und feststellen, welche davon aria-selected=true hat. Das geht mit querySelector:

let currentPage = document.querySelector(".maps .page[aria-selected=true]");

Und dann verwendest Du nicht die pageNumber und rechnest plus/minus 1, sondern Du nutzt das DOM und bestimmst zur gefundenen Page previousElementSibling bzw. nextElementSibling. Das sind die Nachbar-Karten im DOM. Diese Eigenschaften liefern NULL, wenn Du auf dem ersten bzw. letzten Element bist, und mich deucht, dass Du in diesem Fall newPage gar nicht aufrufen musst.

Die Siblings brauchst Du eh - Du ermittelst sie im Moment manuell.

Eigentlich solltest Du newPage mit zwei Parametern aufrufen: Die aktuelle Seite, und der Sibling, der zur neuen Seite werden soll. In newPage kannst Du dann prüfen: Ist die neue Seite null - dann geh gleich wieder raus.

Andernfalls deaktiviere die bisherige Seite und aktiviere die neue Seite.

Das vereinfacht deinen Code deutlich.

Rolf

--
sumpsi - posui - obstruxi