10

I am fetching some data using Apollo inside of Nuxt. Somehow, when navigating to that page I get an error of

Cannot read property 'image' of undefined

When I refresh the page, everything works as expected.

I have a found a few threads of people having similar issues but no solution seems to work for me :/

This is my template file right now:

/products/_slug.vue

<template>
  <section class="container">
    <div class="top">
      <img :src="product.image.url"/>
      <h1>{{ product.name }}</h1>
    </div>
  </section>
</template>

<script>
import gql from 'graphql-tag'

export default {
  apollo: {
    product: {
      query: gql`
        query Product($slug: String!) {
          product(filter: { slug: { eq: $slug } }) {
            slug
            name
            image {
              url
            }
          }
        }
      `,
      prefetch({ route }) {
        return {
          slug: route.params.slug
        }
      },
      variables() {
        return {
          slug: this.$route.params.slug
        }
      }
    }
  }
}
</script>

Basically the $apolloData stays empty unless I refresh the page. Any ideas would be much appreciated

EDIT Got one step closer (I think). Before, everything (image.url and name) would be undefined when navigating to the page for the first time.

I added:

data() {
    return {
      product: []
    };
  }

at the top of my export and now at least the name is always defined so if I remove the image, everything works as expected. Just the image.url keeps being undefined.

One thing I noticed (not sure how relevant) is that this issue only occurs using the , if I use a normal a tag it works but of course takes away the vue magic.

EDIT-2 So somehow if I downgrade Nuxt to version 1.0.0 everything works fine

Martin Conde
  • 345
  • 3
  • 15

3 Answers3

8

I stumbled on this issue as well, and found it hidden in the Vue Apollo documents.

Although quite similar to the OP's reply, it appears the official way is to use the "$loadingKey" property.

It's quite confusing in the documents because there are so many things going on. https://vue-apollo.netlify.com/guide/apollo/queries.html#loading-state

<template>
  <main
    v-if="!loading"
    class="my-8 mb-4"
  >
    <div class="w-3/4 mx-auto mb-16">
      <h2 class="mx-auto text-4xl text-center heading-underline">
        {{ page.title }}
      </h2>
      <div
        class="content"
        v-html="page.content.html"
      ></div>
    </div>
  </main>
</template>
    
<script>
import { page } from "~/graphql/page";
    
export default {
  name: 'AboutPage',

  data: () => ({
    loading: 0
  }),
    
  apollo: {
    $loadingKey: 'loading',
    page: {
      query: page,
      variables: {
        slug: "about"
      }
    },
  }
}
</script>

If you need to use a reactive property within vue such as a slug, you can do so with the following.

<template>
  <main
    v-if="!loading"
    class="my-8 mb-4"
  >
    <div class="w-3/4 mx-auto mb-16">
      <h2 class="mx-auto text-4xl text-center heading-underline">
        {{ page.title }}
      </h2>
      <div
        class="content"
        v-html="page.content.html"
      ></div>
    </div>
  </main>
</template>
    
<script>
import { page } from "~/graphql/page";
    
export default {
  name: 'AboutPage',
    
  data: () => ({
    loading: 0
  }),
    
  apollo: {
    $loadingKey: 'loading',
    page: {
      query: page,
      variables() {
        return {
          slug: this.$route.params.slug
        }
      }
    },
  }
}
</script>
Hendrik Jan
  • 4,396
  • 8
  • 39
  • 75
Rob Mellett
  • 81
  • 1
  • 3
  • 1
    This worked for me. First I tried just setting `$loadingKey: 'loading'`, and it didn't work. But adding `loading: 0` to data fixed it. Im using nuxt apollo. – Nathan Boaldin Mar 29 '20 at 18:11
  • 1
    much appreciated for this - i was having an issue with my query that returns an array of values and it would return undefined whenever i refreshed the page. `$loadingKey` and `v-if` statement worked like a charm – Mike Diglio Sep 11 '20 at 01:29
  • 1
    Thank you so much for this answer! It saved me hours or researching and lots of frustration! – Schwesi Oct 25 '20 at 11:50
4

I think it's only a problem of timing on page load.

You should either iterate on products, if you have more than one, or have a v-if="product != null" on a product container, that will render only once the data is fetched from GraphQL.

In that way you'll use the object in your HTML only when it's really fetched and avoid reading properties from undefined.

mat_jack1
  • 1,712
  • 1
  • 14
  • 15
  • I have tried your idea but somehow it's like it doesn't wait for the data (which should be ssr'd and prefetched anyway) I guess that just adds another issue ;) Made a little progress though if you check my EDIT comment in the main question – Martin Conde Mar 19 '19 at 10:44
  • You are right about the SSR. But then, are you using something like this: https://github.com/nuxt-community/apollo-module ? Nuxt side or is it all in Vue? – mat_jack1 Mar 19 '19 at 10:50
  • Yep I am using the @nuxt/apollo module. I basically followed this example: https://github.com/ErikCH/HeadlessCMSDatoCMS and even if I just clone it and change credentials and queries etc it doesn't work for me so I have no idea what I am doing wrong. – Martin Conde Mar 19 '19 at 10:57
  • it might not work just because you have a different data schema for example. Can you expand on what is actually wrong? – mat_jack1 Mar 20 '19 at 11:04
  • I have thesame issue when ever any of the elements in my query that wasn't set as a nullable value was not set or retured null. but i noticed it wasn't an issue in production just in dev. I would also like to state that i am using "jw-vue-pagination" and with this i face thesame issues you have not withstanding if the above applies or not, but still only in production. – Emmanuel Neni Nov 19 '19 at 16:09
1

To fix this, you add v-if="!$apollo.loading" to the HTML container in which you're taying to use a reactive prop.

Abbas
  • 1,118
  • 1
  • 11
  • 25