Ray Purchase
Ray Purchase

Reputation: 762

NuxtJS - Cannot read property 'title' of undefined - Strange Behaviour

I have a NuxtJS project linked to DatoCMS. A list of posts are displayed, click on a post title etc and get taken to the _slug.vue page displaying more information. When I click on the post title I get taken to the _slug.vue page, where I'm told 'Cannot read property 'title' of undefined'. However, if I refresh that page, it works fine. I can go back and forth between the homepage and the post page without any problems, until I view a different post page, and then the problem happens again until I reload the page. I can't work out what's going on.

index.vue in the Pages directory:

<template>
    <main>
        <div v-for="(post, index) in allPosts" :key="index">
            <div>
                <h3>Generic Header</h3>
                <p>Introduction paragraph</p>
            </div>
            <div>
                <div>
                    <div
                        v-for="(post, index) in allPosts">
                        <ProductCard :post="post"/>
                    </div>
                </div>
            </div>
        </div>
    </main>
</template>

<script>
import ProductCard from "@/components/ProductCard";

import gql from "graphql-tag";

export default {
    components: {
        ProductCard
    },
    apollo: {
        allPosts: gql`
            {
                allPosts {
                    title
                    text
                    slug
                }
            }
        `
    }
};
</script>

The productCard.vue component in the Components directory, which gets called above, has no code in the bottom script tag, just a nuxt-link to the _slug.vue file.

<nuxt-link :to="post.slug" prefetch>{{ post.title }}</nuxt-link>

The _slug.vue file:

<template>
    <div>
        <h1>{{ post.title }}</h1>
        <p>{{ post.text }}</p>
    </div>
</template>

<script>
import gql from "graphql-tag";
export default {
    apollo: {
        post: {
            query: gql`
                query Post($slug: String!) {
                    post(filter: { slug: { eq: $slug } }) {
                        title
                        text
                    }
                }
            `,
            prefetch({ route }) {
                return {
                    slug: route.params.slug
                };
            },
            variables() {
                return {
                    slug: this.$route.params.slug
                };
            }
        }
    }
};
</script>

This is the output from the console:

TypeError: Cannot read property 'title' of undefined
    at Proxy.render (webpack-internal:///./node_modules/vue-loader/lib/loaders/templateLoader.js?!./node_modules/vue-loader/lib/index.js?!./pages/_slug.vue?vue&type=template&id=286199e1&:9)
    at VueComponent.Vue._render (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:3542)
    at VueComponent.updateComponent (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:4049)
    at Watcher.get (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:4473)
    at new Watcher (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:4462)
    at mountComponent (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:4067)
    at VueComponent.Vue.$mount (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:8405)
    at init (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:3115)
    at merged (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:3298)
    at createComponent (webpack-internal:///./node_modules/vue/dist/vue.runtime.esm.js:5968)

I have checked the other answers regarding 'Cannot read property 'title' of undefined' but they don't help in this instance, unfortunately.

Many thanks with any help. 👍 Matt

Upvotes: 2

Views: 1907

Answers (3)

moritzgvt
moritzgvt

Reputation: 444

Could you provide the code of the ProductCard.vue component?

My first assumption based on your question: If there is no code in the script tag you won't be able to use the post property in the template part.

Add this snippet in the script part:

export default {
    name: 'ProductCard',
    props: {
        post: Object
    }
}

Find further information here: https://v2.vuejs.org/v2/guide/components-props.html

Upvotes: 1

Fatih Akgun
Fatih Akgun

Reputation: 553

I had the same error and i came to your post to find an answer but i just fixed it be removing this part from my _slug.vue

data() {
  return {
    categories: [],
  }
},

this is my Links component

<template>
  <div>
    <div
      class="grid w-full grid-cols-1 2xl:grid-cols-4 xl:grid-cols-4 lg:grid-cols-3 sm:grid-cols-2 gap-x-6 gap-y-12"
    >
      <!-- Product Tile Start -->
      <div v-for="link in links" :key="link.id">
        <div>
          <div class="bg-white border rounded-t-lg shadow-sm">
            <div class="relative pb-146/3">
              <img
                class="absolute object-cover w-full h-full rounded-t-lg"
                :src="getStrapiMedia(link.thumbnail.formats.large.url)"
              />
            </div>

            <div class="relative w-full p-4 bg-white">
              <a
                :href="link.url"
                target="_blank"
                class="mb-2 text-base font-medium text-gray-800 truncate hover:text-indigo-500"
              >
                <p class="truncate">{{ link.title }}</p>
              </a>
              <p class="text-xs text-gray-600 truncate">
                {{ link.description }}
              </p>
              <div class="flex flex-wrap items-center mt-6 justify-starts">
                <span
                  v-for="tag in link.tags"
                  :key="tag.id"
                  class="px-2 py-1 mr-1 text-xs leading-none text-indigo-600 bg-indigo-200 rounded"
                  >{{ tag.name }}</span
                >
              </div>
            </div>
          </div>
        </div>
      </div>

      <!-- Product Tile End -->
    </div>
  </div>
</template>

<script>
import { getStrapiMedia } from '../utils/medias'

export default {
  props: {
    links: {
      type: Array,
      default() {
        return []
      },
    },
  },
  methods: {
    getStrapiMedia,
  },
}
</script>

and my pages/_slug.vue where i fixed the issue

<template>
  <div v-if="categories">
    <h1 class="w-full mb-4 text-2xl font-light text-left text-gray-600">
      {{ categories[0].name }}
    </h1>
    <Links :links="categories[0].links || []"></Links>
  </div>
</template>

<script>
import linksQuery from '~/apollo/queries/link/categories'
export default {
  // REMOVING THIS DATA ELEMENT FIXED MY ISSUE
  // data() {
  //   return {
  //     categories: [],
  //   }
  // },
  apollo: {
    categories: {
      prefetch: true,
      query: linksQuery,
      variables() {
        return { slug: this.$route.params.id }
      },
    },
  },
}
</script>

i hope this reference can help any other users

Upvotes: 0

Bartosz Dominiak
Bartosz Dominiak

Reputation: 19

You cannot print uninitialized post object. To avoid this error, just wrap it via v-if="post"

<template>
  <div v-if="post">
    <h1>{{ post.title }}</h1>
    <p>{{ post.text }}</p>
  </div>
</template>

Upvotes: 1

Related Questions