Route Guards SPA+
Per-route leave guards, metadata inheritance, and navigation cancellation. For basic guard setup with beforeEnter and beforeEach, see Route Management.
beforeLeave Guards
Per-route leave guards run when navigating away from a route. Use them to protect against accidental data loss.
Basic Usage
router.onRoute('/editor', {
handler: () => showEditor(),
beforeLeave: ({ to, from }) => {
if (hasUnsavedChanges()) {
return false; // Block navigation
}
return true; // Allow navigation
}
});
Redirect on Leave
router.onRoute('/checkout', {
handler: () => showCheckout(),
beforeLeave: ({ to }) => {
// Must confirm before leaving checkout
if (!orderConfirmed && to.path !== '/confirm-leave') {
return '/confirm-leave'; // Redirect instead
}
return true;
}
});
Guard Return Values
| Return Value | Effect |
|---|---|
true / undefined | Allow leaving the route |
false | Block navigation, stay on current route |
'/path' | Redirect to a different path |
Try it: Navigate to "Edit Form", then try to leave. The guard blocks you until you check "Mark changes as saved".
Route Metadata Inheritance
Child routes inherit their parent's meta properties. Child values override parent values on collision.
const router = wildflower.createRouter({
routes: [
{
path: '/admin',
meta: { requiresAuth: true, layout: 'admin' },
handler: showAdminHome,
children: [
{
path: '/users',
meta: { requiresAdmin: true },
handler: showAdminUsers
// Effective meta: { requiresAuth: true, layout: 'admin', requiresAdmin: true }
},
{
path: '/settings',
meta: { layout: 'settings' }, // Overrides parent layout
handler: showSettings
// Effective meta: { requiresAuth: true, layout: 'settings' }
}
]
}
]
});
// Use in a global guard
router.beforeEach(({ to }) => {
if (to.meta.requiresAuth && !isLoggedIn()) {
return '/login';
}
if (to.meta.requiresAdmin && !isAdmin()) {
return '/unauthorized';
}
return true;
});
Navigation Cancellation
Cancel an in-progress navigation from outside the guard chain using abortNavigation():
// Start a navigation
router.navigate('/slow-page');
// Cancel it before it completes
router.abortNavigation();
// Practical example: timeout protection
router.navigate('/api-data');
const timeout = setTimeout(() => {
if (router.isNavigating) {
router.abortNavigation();
showTimeoutError();
}
}, 5000);
Timing:
abortNavigation() only works while router.isNavigating is true. It has no effect after navigation completes.
SPA
E-commerce Store
A checkout flow that refuses to advance past an empty cart, guarded at the route.