Vue Router: Reacting to parameter changes

The Vue Router doesn't re-render a component when a route parameter is changed. When you have a Vue component that uses route params, you need to write additional code to react to changes in the parameters. This issue is explained in this Vue Router guide page.

Before Reading

This page assumes that you have already included the prismic-vue plugin and are using Vue Router in your project. Check out the Integrating with existing project page to learn how to get setup.

Querying content from Prismic based on route params

You need to make sure to pay attention to parameter changes in a Vue component if it needs to get the route parameters to query the Prismic API. For example, some of your Vue app routes can be defined with a UID or the language code of a Prismic document. In which case, the Vue component mapped to the concerned route will get this Prismic value and use it to query the API.

What happen if you don't react to parameter changes

If you do not explicitly react to parameter changes in your project, you will run into one main issue. When you click on a link to an internal route, the URL will change in your browser but your webpage will not actually update. If this is happening in your project, read the following section to learn how to solve this issue.

Additional code required to react to parameter changes

To handle this issue, you just need to add a bit of code in the beforeRoutUpdate guard. Inside it, you have access to the destination route params. All you need to do is use that route parameter to make a call to your getContent method. This will update your template with the correct Prismic content based on the intended route.

The following is a basic example of how to fix this issue. In this case, the Vue component uses the Prismic document UID as a route parameter.

Copy
methods: {
  getContent (uid) {
    this.$prismic.client.getByUID('your_custom_type_api_id', uid)
      .then((document) => {
        // ... here is your handling of the document content
      })
  }
},
created () {
  this.getContent(this.$route.params.uid);
},
beforeRouteUpdate (to, from, next) {
  this.getContent(to.params.uid);
  next();
}

Full example: blog posts

For those who are curious, we will now go through a complete example of how this issue might arise. Let's take this simple case of blog posts in Prismic that use the UID field for their URLs. We will assume this blog uses this URL pattern: https://example.com/blog/{Prismic-document-UID}.

This example will use the following repeatable Custom Type with an API ID of "blog_post". This type contains a UID field and a Rich Text field. Here is its JSON definition:

Copy
{
  "Main" : {
    "uid" : {
      "type" : "UID",
      "config" : {
        "label" : "UID"
      }
    },
    "rich_content" : {
      "type" : "StructuredText",
      "config" : {
        "multi" : "paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item",
        "allowTargetBlank" : true,
        "label" : "Rich content"
      }
    }
  }
}

In the Vue Router configuration of the project, you would need to define a route for the blog posts containing a parameter for the document UID:

Copy
import Vue from 'vue';
import Router from 'vue-router';
import BlogPost from 'path/to/BlogPost.vue';

Vue.use(Router);

const router = new Router({
  routes: [
    {
      path: '/blog/:uid',
      name: 'blog-post',
      component: BlogPost
    }
  ]
});

export default router;

You would also need to define the blog URLs in your Link Resolver function to match the route defined above:

Copy
export default function (doc) {
  if (doc.isBroken) {
    return '/not-found';
  }

  if (doc.type === 'blog_post') {
    return '/blog/' + doc.uid;
  }

  return '/not-found';
};

Let assume the content is rendered in a Vue component named BlogPost.vue. We need to make sure to add the proper code to the beforeRouteUpdate guard. When a parameter change occurs, the component will call the getContent method with the document UID of the destination route. This way, when a website visitor clicks on a link to another blog post, the content will be updated correctly.

Copy
<template>
  <div>
    <prismic-rich-text :field="fields.richContent"/>
  </div>
</template>

<script>
export default {
  name: 'BlogPost',
  data () {
    return {
      fields: {
        richContent: null
      }
    };
  },
  methods: {
    getContent (uid) {
      this.$prismic.client.getByUID('blog_post', uid)
        .then((document) => {
          this.fields.richContent = document.data.rich_content;
        })
    }
  },
  created () {
    this.getContent(this.$route.params.uid);
  },
  beforeRouteUpdate (to, from, next) {
    this.getContent(to.params.uid);
    next();
  }
};
</script>