How to dynamically set meta title, description, and image in a Vue.js application using Vue Unhead and Vue Meta?

635 Views Asked by At

I am working on a Vue.js project where I need to set the meta title, description, and image dynamically based on the data I receive from an API. I'm using Vue Vue Unhead and Vue Meta to handle the meta tags. Here's the relevant code in my project:

In main.js:

import "./assets/main.css";

import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import "./plugins";
// import { createMetaManager } from "vue-meta";
import { createHead } from '@unhead/vue'

const app = createApp(App);
app.use(router);
app.use(store);
// app.use(createMetaManager()); // Use Vue Meta plugin
const head = createHead()
app.use(head)
app.mount("#app");

On the detail page onMounted function, I am calling a function which will call the API and fetch the data using axios

import { onMounted } from "vue";
import axios from "axios";

onMounted(() => {
  fetchOperatorDetail();
});

function fetchOperatorDetail() {
  axios.get(
    `api/route`,
    {
      headers: {
        'time_zone': timeZone,
      }
    }
  ).then((response) => {
    if (Object.keys(response.data.data).length > 0) {
      // Extract data from the API response
      // How can I set this data to the meta title, description, and image dynamically?
    }
  });
}

The ultimate goal is when I share the URL of the detail page to any platform it should display the meta title, and description along with the image.

I have tried setting static text for the meta title, but I'm struggling to dynamically update the description and image based on the API response. Can anyone guide me on how to achieve this using Vue Unhead and Vue Meta or suggest an alternative approach?

Additional context:

  1. I've already tried using Vue Unhead and Vue Meta for setting the meta tags.
  2. The project is built with Vue.js version 3.

UPDATE My Index.js looks like this

import { createRouter, createWebHistory } from "vue-router";
import ListView from "../components/views/ListView.vue";
import { nextTick } from "vue";

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: "/",
      name: "home",
      component: ListView,
     // meta: { title: "ListView" },
    },
    {
      path: "/:detailpage/:packageid?",
      name: "detailpage",
      component: () => import("../components/views/detail page.vue"),
      //meta: { title: "detail page" },
    },
  ],
});

// const DEFAULT_TITLE = "detailpage";

// router.afterEach((to, from) => {
//   nextTick(() => {
//     document.title = to.meta.title || DEFAULT_TITLE;
//   });
// });

export default router;
2

There are 2 best solutions below

4
On

Use useHead in Vue Unhead

import { onMounted } from "vue";
import axios from "axios";
import { useHead } from '@unhead/vue'

const title = ref('')
useHead({
  title,
})

onMounted(() => {
  fetchOperatorDetail();
});

function fetchOperatorDetail() {
  axios.get(
    `api/route`,
    {
      headers: {
        'time_zone': timeZone,
      }
    }
  ).then((response) => {
    if (Object.keys(response.data.data).length > 0) {
      // Extract data from the API response
      title.value = response.data.data.title || ''
    }
  });
}

Here is docs

2
On

You have to use functions instead of fixed values to get reactive title and meta description working.

import { useHead } from '@unhead/vue';

const titleFromApi = ref('');
const descriptionFromApi = ref('');

useHead({
  title: () => titleFromApi.value,
  meta: () => [
    { name: 'description', content: descriptionFromApi.value }
  ]
});