Hallo borisbaer,
dass ich einen Timer brauche nach dem fetch(), da sonst das script change-page zu schnell ausgeführt wird,
Hattest Du den changePage-Aufruf, den Du derzeit im Timer hast, vorher in dem .then-Aufruf des fetch, wo Du das DOM veränderst?
.then( ( html ) => {
mapsWrapper.innerHTML = html;
changePage( true );
})
sollte eigentlich funktionieren.
Und ja, changePage(true), nicht changePage(reset=true). Du tust so, als wäre das ein Funktionsparameter. Aber changePage nimmt gar keinen Parameter entgegen, statt dessen definiert change-page.js eine globale Variable reset und die setzt Du während der Parameterübergabe flugs.
Ändere change-page.js so, dass let reset;
wegfällt und schreibe dort
const changePage = (reset) => {
...
}
Dann klappt das auch mit der Übergabe eines reset-Parameters.
Deine click-Handler Steuerung ist gruselig, du fummelst da instinktiv mit Closures herum und weißt vermutlich nicht einmal, was das ist.
Wenn Du die maps Subpage erstmalig aufrufst, wird changePage ausgeführt. Darin setzt Du eine Variable page, mit einer Liste der Karten, die gezeigt werden. Und dann erzeugst Du eine newPage-Funktion - lokal zu changePage - und registrierst anonyme Funktionen - lokal zu changePage - als Eventhandler. Damit beginnt das Drama, denn die newPage-Funktion, die so entstanden ist, enthält einen Verweis auf den Variablenkontext, in dem sie definiert wurde. Das sind die lokalen Variablen von dem changePage-Aufruf, der diese newPage Funktion erzeugt hat. newPage schließt diese Variablen mit ein - das ist die Closure.
changePage endet, aber die click- und keydown-Handler bleiben. Und damit auch die lokalen Variablen von changePage. Deswegen und NUR deswegen funktioniert das Blättern, die Closure mit den Variablen von changePage liefert alles nötige.
Soweit, so gut, aber wenn Du nun einen neuen Kartensatz lädst, rufst Du changePage(true) auf - für den Reset. Den führst Du aber nicht vollständig aus. Die alten click-Handler auf den Pfeilen und auch der keydown-Handler auf dem Body bleiben erhalten, und damit auch die Closure mit den page-Verweisen auf die vorige Karte. Diese Eventhandler laufen dann auf der neuen Karte munter mit, und crashen natürlich, weil die Kartenseiten aus dem DOM gelöscht wurden und keinen parentNode mehr haben.
Der neue changePage Aufruf definiert wiederum eine newPage Funktion. Beachte: Dies ist eine andere Funktion wie die aus dem ersten changePage Aufruf. Sie ist lokal zu changePage, sie existiert nur in diesem einen Aufrufkontext. Die lokale Variable, in der Du sie speicherst, heißt zwar gleich, aber trotzdem ist es eine andere Funktion. Der Hauptunterschied ist: Die Closure über die lokalen changePage-Variablen ist eine andere.
Wie kommt man da jetzt heraus?
In dem Moment, wo Du die Maps Seite verlässt, werden die Pfeile aus dem DOM gelöscht und damit auch alle Eventhandler, die daran hängen. Der keydown-Handler auf dem Body bleibt aber erhalten - der kriegt Dich auch dann noch am Allerwertesten, wenn Du die Subpage wechselst, z.B. nach Mods und wieder zurück. Nur - das merkst Du nicht. Du hast die komplette Subpage weggeschmissen, inclusive des draggable Wrappers, und dieser Zombie-Verein klammert sich jetzt verzweifelt über eine Closure am keydown-Handler fest und blättert fleißig im Nichts vor sich hin.
Also: erstmal dringend den keydown-Handler vom Body auf den draggable Wrapper verlegen, damit der einen Subpage-Wechsel nicht überlebt.
Und nun wird's schwieriger: Das Entfernen der alten Eventhandler. Das ist de facto so schwierig, dass ich für den Wechsel der abgefragten Karte generell davon abraten würde. Versuche statt dessen, die Eventhandler für die Links- und Rechtsklicks sowie den keydown-Handler so zu bauen, dass sie keine Kontextinformationen brauchen und alles, was sie brauchen, aus dem aktuellen DOM beziehen. Wenn das erreicht ist, kannst Du auf Closure-Daten aus dem changePage Aufruf verzichten und brauchst die Eventhandler nicht neu zu registrieren. Das wäre mein Vorgehen. Trivial ist es nicht, aber ich denke, ziemlich robust. Die Alternative wäre ein Datenspeicher mit den erforderlichen Steuerinformationen für die Eventhandler, den Du beim Wechsel des Kartensets aktualisieren müsstest. Oder ein globaler Speicher für die alten Eventhandler-Funktionen, womit du diese deregistrieren könntest. Alles Brrr. Hantieren auf dem aktuellen DOM ist der einfachste Weg.
Du kannst auch DOM Objekten eigene Eigenschaften hinzufügen.
const wrap = document.querySelector(".maps .wrapper");
wrap.boris.daten = {
foo: 1,
bar: 2
};
Und schon hat das Wrapper div eine Eigenschaft boris, die außer Dir keiner kennt und wo Du Dinge speichern kannst. Z.B. wieviele Kartenteile Du hast und welches Teil aktiv ist. Aber gerade das brauchst Du ja eigentlich nicht. Du kannst mit querySelectorAll die Anzahl der Kartenteile finden, und die gerade angezeigte Karte kannst Du mit dem Attribut aria-selected=true markieren und wiederfinden. Du solltest auf ein Anhängsel dieser Art nach aller Möglichkeit verzichten.
Rolf
sumpsi - posui - obstruxi