Programmatic Navigation and Guards
<RouterLink> handles declarative navigation — the user clicks a link. But often you need to navigate in response to events, form submissions, or conditions. That’s programmatic navigation.
useRouter and router.push
Section titled “useRouter and router.push”useRouter() returns the router instance. Call router.push() to navigate:
<script setup lang="ts">import { useRouter } from 'vue-router'
const router = useRouter()
function handleSubmit(personId: string) { // After saving, navigate to the detail page router.push({ name: 'person', params: { id: personId } })}
function goHome() { router.push({ name: 'home' })}</script>router.push() adds an entry to the browser history — the back button works. router.replace() replaces the current entry instead — the back button skips the replaced page.
In FamilyTree
Section titled “In FamilyTree”PersonDetailView.vue uses programmatic navigation when the user deletes a person:
function handleDelete() { if (!confirm(`Delete ${person.value?.name}? This cannot be undone.`)) return store.deletePerson(id) router.push({ name: 'home' }) // return home after deletion}
function focusOn(pid: string) { store.setFocus(pid) router.push({ name: 'home' }) // navigate to home with new focus}Navigation guards
Section titled “Navigation guards”Guards intercept navigation and can allow, redirect, or cancel it. The most common is the global beforeEach guard, registered on the router:
router.beforeEach((to, from) => { // to: the route being navigated to // from: the route being navigated from
// Return false to cancel navigation // Return a route location to redirect // Return nothing (or true) to allow})Protecting a route
Section titled “Protecting a route”A simple guard that requires data before viewing a person’s details:
router.beforeEach((to, from) => { if (to.name === 'person') { const store = useFamilyStore() const exists = store.people.some(p => p.id === to.params.id) if (!exists) { return { name: 'home' } // redirect home if person doesn't exist } }})Per-route guards
Section titled “Per-route guards”Guards can also be defined on individual route records:
{ path: '/admin', component: AdminView, beforeEnter: (to, from) => { if (!isAdmin()) return { name: 'home' } }}Exercise
Section titled “Exercise”- Add programmatic navigation to a form’s submit handler: after “saving” (just
console.logfor now), push to{ name: 'home' }. - Add a global
beforeEachguard that logs"Navigating to: " + to.namefor every navigation. - Extend the guard to redirect to
{ name: 'home' }if the user tries to navigate to{ name: 'person' }with an id that doesn’t exist in the store.
useRouter()returns the router instance; callrouter.push(location)to navigate programmatically.router.push()adds history;router.replace()replaces the current entry.router.beforeEach((to, from) => {...})runs before every navigation — return a route to redirect,falseto cancel, or nothing to allow.- Per-route
beforeEnterguards work the same way for a single route.