N
Nuxt2mo ago
CFHxKai

How to prevent navigation in nested routes?

I have a route like /[firstId]/[secondId]. The page [firstId] has a list of links to navigate and a <NuxtPage /> to load a page with the form from secondId data, but before change between nested secondId's routes I'm checking if the form is dirty and trying to prevent navigation asking to user if he really wants to leave and lost the changes. But in nested page the onBeforeRouteLeave don`t work. There is another way to achieve this? Thank you 👍
3 Replies
kapa.ai
kapa.ai2mo ago
Hi @CFHxKai. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- To prevent navigation in nested routes, especially when dealing with forms and unsaved changes, you can use a combination of route middleware and navigation guards. Here's how you can approach this: 1. Use onBeforeRouteLeave in your nested page component: While you mentioned that onBeforeRouteLeave doesn't work in your nested page, it should actually work. Make sure you're importing and using it correctly:
import { onBeforeRouteLeave } from 'vue-router'

// In your component setup
onBeforeRouteLeave((to, from) => {
if (formIsDirty()) {
// Ask user for confirmation
if (!confirm('You have unsaved changes. Are you sure you want to leave?')) {
return false // Prevent navigation
}
}
})
import { onBeforeRouteLeave } from 'vue-router'

// In your component setup
onBeforeRouteLeave((to, from) => {
if (formIsDirty()) {
// Ask user for confirmation
if (!confirm('You have unsaved changes. Are you sure you want to leave?')) {
return false // Prevent navigation
}
}
})
Source (https://nuxt.com/docs/api/utils/on-before-route-leave) 2. Use route middleware: If onBeforeRouteLeave is still not working as expected, you can create a named route middleware to handle this check:
// middleware/check-form.ts
export default defineNuxtRouteMiddleware((to, from) => {
// Check if the form is dirty (you'll need to implement this logic)
if (formIsDirty()) {
// Ask user for confirmation
if (!confirm('You have unsaved changes. Are you sure you want to leave?')) {
return abortNavigation()
}
}
})
// middleware/check-form.ts
export default defineNuxtRouteMiddleware((to, from) => {
// Check if the form is dirty (you'll need to implement this logic)
if (formIsDirty()) {
// Ask user for confirmation
if (!confirm('You have unsaved changes. Are you sure you want to leave?')) {
return abortNavigation()
}
}
})
Then, apply this middleware to your nested route:
<script setup>
definePageMeta({
middleware: ['check-form']
})
</script>
<script setup>
definePageMeta({
middleware: ['check-form']
})
</script>
Source (https://nuxt.com/docs/guide/directory-structure/middleware) 3. Use useRouter for global navigation guards: If you want to apply this check globally, you can use the useRouter composable:
const router = useRouter()
router.beforeEach((to, from) => {
if (formIsDirty()) {
// Ask user for confirmation
if (!confirm('You have unsaved changes. Are you sure you want to leave?')) {
return false // Prevent navigation
}
}
})
const router = useRouter()
router.beforeEach((to, from) => {
if (formIsDirty()) {
// Ask user for confirmation
if (!confirm('You have unsaved changes. Are you sure you want to leave?')) {
return false // Prevent navigation
}
}
})
Source (https://nuxt.com/docs/api/composables/use-router#navigation-guards) Remember that route middleware runs within the Vue part of your Nuxt app, making it suitable for this kind of client-side navigation guard Source (https://nuxt.com/docs/guide/directory-structure/middleware). By implementing one or a combination of these approaches, you should be able to prevent navigation when the form is dirty, even in nested routes. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2mo ago
<@206534948952342529> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
CFHxKai
CFHxKaiOP2mo ago
1. give the same problem reported. 2. I think not work in this case because middleware run after leave and before enter (right? :P), and if leave the page I will lost page/components states (form changes). 3. do the trick, but need clean the beforeEach on leave (unmount page) to prevent register a new listener in each page change:
const router = useRouter();

const stop = router.beforeEach(() => {
if (!myForm.value?.isDirty) return;

if (!confirm('You have unsaved changes. Are you sure you want to leave?')) {
return false;
}
});

onUnmounted(() => {
stop();
});
const router = useRouter();

const stop = router.beforeEach(() => {
if (!myForm.value?.isDirty) return;

if (!confirm('You have unsaved changes. Are you sure you want to leave?')) {
return false;
}
});

onUnmounted(() => {
stop();
});
Don't know if is the better solution, but I don't find a better way to solve. ^^ Thank you... 😉
Want results from more Discord servers?
Add your server