Signatur
Beschreibung
Das Interface NavigationPrecommitController gehört zur Navigation API. Sie bekommen nie selbst eine Instanz davon, sondern erhalten ein Objekt als einziges Argument, wenn Sie in NavigateEvent.intercept() die Option precommitHandler angeben. Der Browser ruft diesen Handler auf, bevor die Navigation festgeschrieben wird. Bis dahin haben sich die URL in der Adressleiste und navigation.currentEntry noch nicht geändert.
In dieser Phase können Sie noch entscheiden, wohin die Navigation geht. Die zentrale Methode dafür ist controller.redirect(url, options). Sie ändert das Ziel der laufenden Navigation und kann optional state, info und das Verlaufsverhalten (history) neu setzen. Anders als ein nachträgliches navigation.navigate() entsteht dabei kein zusätzlicher, ungewollter Eintrag im Verlauf.
Typische Einsätze sind:
- Zugriffsprüfung: Nicht angemeldete Nutzer schicken Sie auf
/login, bevor die geschützte URL überhaupt sichtbar wird. - Kanonische URLs: Veraltete Pfade oder Kurzlinks leiten Sie auf das richtige Ziel um.
- Daten vorladen: Kritische Daten laden Sie vor dem Commit, damit die neue URL erst erscheint, wenn der Inhalt bereit ist.
Wenn das vom precommitHandler zurückgegebene Promise erfüllt wird, schreibt der Browser die Navigation fest. Danach läuft der normale handler. Wird das Promise abgelehnt, bricht die Navigation ab und navigateerror wird ausgelöst.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $url Pflicht | string | URL | Parameter von redirect(): das neue Navigationsziel. Relative URLs werden gegen die Dokument-URL aufgelöst. Die URL muss denselben Ursprung haben wie das Dokument. |
|
| $options | object | {} | Parameter von redirect(): optionales Objekt mit den folgenden Feldern. |
| $options.state | any | Neuer Zustand für den Verlaufseintrag. Er muss per structured clone kopierbar sein und ist später über navigation.currentEntry.getState() abrufbar. |
|
| $options.info | any | Flüchtige Zusatzinformation, die über NavigateEvent.info weitergereicht wird. Sie wird nicht im Verlauf gespeichert. |
|
| $options.history | "auto" | "push" | "replace" | "auto" | Legt fest, ob die umgeleitete Navigation einen neuen Verlaufseintrag anlegt ("push") oder den aktuellen ersetzt ("replace"). |
Rückgabewert
redirect() gibt undefined zurück. Die Wirkung zeigt sich nur darin, dass die laufende Navigation ein neues Ziel bekommt. Ob die Navigation abgeschlossen wird, hängt vom Promise ab, das der precommitHandler zurückgibt.Beispiele
Geschützte Route: vor dem Commit auf /login umleiten
const isLoggedIn = () => document.cookie.includes('session=');
navigation.addEventListener('navigate', (event) => {
const url = new URL(event.destination.url);
// Nur eigene, abfangbare Navigationen unter /konto behandeln
if (!event.canIntercept || !url.pathname.startsWith('/konto')) return;
event.intercept({
// Läuft VOR dem Commit – die Adressleiste zeigt noch die alte URL
precommitHandler: async (controller) => {
if (!isLoggedIn()) {
const ziel = encodeURIComponent(url.pathname);
controller.redirect(`/login?weiter=${ziel}`, { history: 'replace' });
}
},
// Läuft NACH dem Commit mit der endgültigen URL
handler: async () => {
const pfad = new URL(navigation.currentEntry.url).pathname;
document.querySelector('main').textContent = `Seite: ${pfad}`;
}
});
});
Veraltete URLs auf kanonische Pfade umschreiben
const umleitungen = new Map([
['/blog/alt-artikel', '/artikel/neuer-artikel'],
['/hilfe', '/support']
]);
navigation.addEventListener('navigate', (event) => {
if (!event.canIntercept) return;
const { pathname } = new URL(event.destination.url);
const neu = umleitungen.get(pathname);
if (!neu) return;
event.intercept({
precommitHandler: (controller) => {
controller.redirect(neu, {
state: { umgeleitetVon: pathname },
info: { grund: 'kanonisch' }
});
},
handler: async () => {
console.log('Jetzt auf:', new URL(navigation.currentEntry.url).pathname);
console.log('State:', navigation.currentEntry.getState());
}
});
});
Daten vor dem Commit laden, mit Feature-Erkennung
const unterstuetztPrecommit = 'NavigationPrecommitController' in window;
navigation.addEventListener('navigate', (event) => {
if (!event.canIntercept || event.navigationType === 'reload') return;
const url = new URL(event.destination.url);
let daten;
const laden = async () => {
const res = await fetch(`/api${url.pathname}`, { signal: event.signal });
if (res.status === 404) return null;
return res.json();
};
event.intercept(unterstuetztPrecommit ? {
precommitHandler: async (controller) => {
daten = await laden();
// Unbekannte Seite: auf die 404-Seite umleiten, statt eine kaputte URL festzuschreiben
if (daten === null && event.navigationType !== 'traverse') {
controller.redirect('/nicht-gefunden', { history: 'replace' });
}
},
handler: async () => render(daten)
} : {
// Fallback ohne Precommit-Unterstützung
handler: async () => render(await laden())
});
});
const render = (daten) => {
document.querySelector('main').textContent = daten ? daten.titel : 'Nicht gefunden';
};