10

I'm building a web application using vue.js v1.0, vue-router v0.7 and WebPack. I'm following Single File Component pattern and have different components for each page.

I don't know how I could change page title in different routings (or maybe different components) when I am navigating through the web app pages. I also want page titles to be available in browser history.

jmosawy
  • 758
  • 1
  • 8
  • 20

3 Answers3

12

In addition to my earlier solution posted here, there is a second method that I found after a bit of research: use Navigation Guards

As detailed in my previous answer, here is the problem: vue-router may start reusing route components after getting created for the first time. There is really no need to destroy these components on route-exit, and re-create on subsequent route-entry. Therefore the created hook in my earlier solution may not fire on subsequent visits to the same route. Therefore our window title may not work as expected.

To overcome that problem, we can set the window title on a route-change event. The router instance has a afterEach hook that gets called after route change. This can be used to set window title as detailed below:

// Let's say this is your router instance, with all "Named Routes"
const ROUTER_INSTANCE = new VueRouter({
    mode: "history",
    routes: [
        { path: "/", name: "HomeComponentName", component: HomeComponent },
        { path: "/about", name: "AboutComponentName", component: AboutComponent },
        { path: "*", name: "RouteErrorName", component: RouteError }
    ]
})

// Assign page titles for each of the "named routes"
// Reason: This allows us to have short named routes, with descriptive title
const PAGE_TITLE = {
    "HomeComponentName": "Your Dashboard",
    "AboutComponentName": "About Us Page",
    "RouteErrorName": "Error: Page not found"
}

ROUTER_INSTANCE.afterEach((toRoute, fromRoute) => {
    window.document.title = PAGE_TITLE[toRoute.name]
    console.log(toRoute)  // this lets you check what else is available to you here
})

This may still not help you if you are navigating between similar routes, like "/user/foo" to "/user/bar". If you want user name in the titlebar or some dynamic page specific info, check out Reacting to Params Changes as detailed in http://router.vuejs.org/en/essentials/dynamic-matching.html. Based on docs, we should be able to use watch in component as follows:

watch: {
    '$route' (toRoute, fromRoute) {
        window.document.title = "some page title"
    }
}

Hope it helps!

Mani
  • 23,635
  • 6
  • 67
  • 54
  • This is a perfect, simple solution. I put the object and the `afterEach` in the root Vue component's `mounted()` function. As the list of pages grows, it might be worth it to extract it elsewhere. (TBH: I had totally forgotten you could set the window title via JS!) – Ryan Ginnow May 23 '19 at 19:11
4

I also had the same problem few days ago, and I resolved as follows in my route component definition:

export default {
    created: function() {
        window.document.title = "Page Title for this route"
        ...
    },
    ...
}

That's really not the correct way of doing it. Reason: I am making a big assumption that the route component gets created everytime on changing to a new route. It is true in vue-router for now, but may change in future.

I was using ui-router in Angular 1.4 earlier, which allows route components to live in memory (sticky states), so that the route change is instantaneous next time. If vue-router ever implements something similar to sticky states, my above method of setting title in created hook will fail.

But till that happens, you may use this solution.

Mani
  • 23,635
  • 6
  • 67
  • 54
  • Do you mean "_root_ component" instead of "route component"? – Dzamo Norton Sep 12 '18 at 03:07
  • I meant the route component only, the one that renders inside ``. If we change window title inside its mounted hook, it will work for the first time. But later when the old component instance gets reused, the mounted hook may not run and therefore window title will not update. – Mani Sep 12 '18 at 03:35
3

I've got a solution and used it on one my projects.

First create a directive.

Vue.directive('title', {
  inserted: (el, binding) => document.title = binding.value,
  update: (el, binding) => document.title = binding.value
})

Suppose, we are working on 'MyComponent.vue' file.

Then use that directive on the router-view component.

<router-view v-title="title" ></router-view>

export default {
  data(){
    return {
      title: 'This will be the title'
    }
  }
}

This works even if the component is updated or the page is reloaded.

Worked very well for me!!

Faiyaz Shaikh
  • 127
  • 3
  • 10