#vue #javascript #frontend

Day 11: Dynamic Routing & Guards

Welcome to Day 11! Yesterday we learned basic navigation. Today, we handle dynamic data in URLs and security.

Dynamic Route Matching

Often we map routes to a pattern like /user/john or /user/123. We use a colon : to denote a param.

router/index.ts

{
  path: '/user/:id',
  name: 'user-profile',
  component: UserProfile
}

Accessing Params in Component Use the useRoute() composable (not useRouter).

<script setup lang="ts">
import { useRoute } from 'vue-router'
import { watch } from 'vue'

const route = useRoute()

// route.params.id matches the real ID
console.log(route.params.id)

// Important: React to changes!
// If you go from /user/1 to /user/2, the component is REUSED.
watch(
  () => route.params.id,
  (newId) => {
    // fetch new user data...
    console.log('User changed to', newId)
  }
)
</script>

<template>
  <h1>User Profile: {{ route.params.id }}</h1>
</template>

404 Not Found Page

How do we catch “everything else”?

{
  // Regex pattern matching everything
  path: '/:pathMatch(.*)*',
  name: 'not-found',
  component: NotFoundView
}

You often want to protect routes (e.g., specific to “Admin” or “LoggedIn”).

Global Before Guard

Runs before every navigation.

router/index.ts

router.beforeEach((to, from) => {
  const isAuthenticated = false // fake check

  // Check custom meta field
  if (to.meta.requiresAuth && !isAuthenticated) {
    // redirect to login
    return { name: 'login' }
  }
  // All good, proceed
})

Defining Meta Fields

{
  path: '/dashboard',
  component: Dashboard,
  meta: { requiresAuth: true }
}

Challenge for Day 11

  1. Create a “Product Detail” route /product/:id.
  2. Add a route guard that prevents access to /product/999 (simulating a banned item) and redirects to home.
  3. In the Product Detail component, display the id.

Solution:

router/index.ts

const router = createRouter({
  // ...
  routes: [
    { 
      path: '/product/:id', 
      component: ProductDetail 
    }
  ]
})

router.beforeEach((to) => {
  // If we are going to product detail
  if (to.path.startsWith('/product/')) {
    const id = to.params.id
    if (id === '999') {
      alert('Product 999 is banned!')
      return '/'
    }
  }
})

ProductDetail.vue

<script setup lang="ts">
import { useRoute } from 'vue-router'
const route = useRoute()
</script>

<template>
  <h1>Viewing Product #{{ route.params.id }}</h1>
</template>

Navigate cleanly and safely! Tomorrow, we tackle the big beast: State Management with Pinia.