Chris
Chris

Reputation: 124

Vue Router 4 - nested 404 (not found) routes redirect not working

these are my routes:

const routes: Array<RouteRecordRaw> = [
  {
    path: "/projects",
    component: {},
    children: [
      { path: "extensions", component: {} },
      { path: "themes", component: {} },
      { path: ":pathMatch(.*)*", redirect: "extensions" },
    ],
  },
  {
    path: "/about",
    component: {},
    children: [
      { path: "experience", component: {} },
      { path: "documents", component: {} },
      { path: ":pathMatch(.*)*", redirect: "experience" },
    ],
  },
  { path: "/:pathMatch(.*)*", redirect: "/projects/extensions" },
];

Expected result:

Navigating to /projects or /projects/asdasd -> redirects to /projects/extensions
Navigating to /about or /about/asdasd -> redirects to /about/experience
Navigating to /asdasdasd -> redirects to /projects/extensions


Current result:
Every incorrect path redirects me to /projects/extensions

I tried many combinations but nothing works as expected, please help.

Upvotes: 2

Views: 1606

Answers (1)

tony19
tony19

Reputation: 138216

Redirecting to child route

To redirect /projects to /projects/extensions, add a child route with a blank path that redirects to the target route:

const routes: Array<RouteRecordRaw> = [
  {
    path: "/projects",
    component: () => import("../views/ProjectsView.vue"),
    children: [
      {
        path: "",
        redirect: "/projects/extensions", // or use a named route (see below)
      },
      ⋮
    ],
  },
}

Getting the redirect target right

When the redirect string is not an absolute path to a route (i.e., /about/experience), the path would be relative to the current route.

For instance, imagine being at /projects/themes and clicking /about/foo. This is how the final route would resolve:

  1. /about/foo matches the wildcard route under /about, which redirects to /projects/themes/experience.

  2. /projects/themes/experience matches the outer wildcard route, which redirects to /projects/extensions.

There are a couple ways to solve this...

Option 1: Use absolute path in redirect string

const routes: Array<RouteRecordRaw> = [
  {
    path: "/projects",
    component: () => import("../views/ProjectsView.vue"),
    children: [
      {
        path: "extensions",
        component: () => import("../views/ProjectsExtensions.vue"),
      },
      {
        path: "themes",
        component: () => import("../views/ProjectsThemes.vue"),
      },                                       👇
      { path: ":pathMatch(.*)*", redirect: "/projects/extensions" },
    ],
  },
  {
    path: "/about",
    component: () => import("../views/AboutView.vue"),
    children: [
      {
        path: "experience",
        component: () => import("../views/AboutExperience.vue"),
      },
      {
        path: "documents",
        component: () => import("../views/AboutDocuments.vue"),
      },                                       👇
      { path: ":pathMatch(.*)*", redirect: "/about/experience" },
    ],
  },                                       👇
  { path: "/:pathMatch(.*)*", redirect: "/projects/extensions" },
]

demo 1

Option 2: Use named route in redirect object

const routes: Array<RouteRecordRaw> = [
  {
    path: "/projects",
    component: () => import("../views/ProjectsView.vue"),
    children: [
      {
        path: "extensions",
          👇
        name: "proj-ext",
        component: () => import("../views/ProjectsExtensions.vue"),
      },
      {
        path: "themes",
        component: () => import("../views/ProjectsThemes.vue"),
      },                                       👇
      { path: ":pathMatch(.*)*", redirect: { name: "proj-ext" } },
    ],
  },
  {
    path: "/about",
    component: () => import("../views/AboutView.vue"),
    children: [
      {
        path: "experience",
          👇
        name: "about-exp",
        component: () => import("../views/AboutExperience.vue"),
      },
      {
        path: "documents",
        component: () => import("../views/AboutDocuments.vue"),
      },                                       👇
      { path: ":pathMatch(.*)*", redirect: { name: "about-exp" } },
    ],
  },                                        👇
  { path: "/:pathMatch(.*)*", redirect: { name: "proj-ext" } },
]

demo 2

Named routes are easier to maintain than paths, as (1) they avoid having to enter long paths, and (2) they could be moved without having to refactor paths.

Upvotes: 2

Related Questions