Access nested nodes with GraphQL (Nuxt)

Viewed 227

i’m experiencing some issues with Apollo, GraphQL and Nuxt. i don’t know if it’s especially related to Nuxt though, or with vue.

i’m trying to use WordPress as headless CMS via WP-GraphQL plugin. here’s my query

WP-GraphQL interface

i basically created a graphql folder with a posts.js file inside, that contains my query

import gql from 'graphql-tag'
export const myQuery = gql`
  query myQuery {
    posts {
      nodes {
        id
        title
        date
        slug
        author {
          node {
            name
          }
        }
        featuredImage {
          node {
            uri
            sourceUrl
            srcSet
          }
        }
      }
    }
  }
`

then, all i need to do is to print my data in the template. here's the script part first.

<script>
import { myQuery } from '~/graphql/posts'

export default {
  data() {
    return {
      posts: [],
    }
  },

  apollo: {
    posts: {
      prefetch: true,
      query: myQuery,
    },
  },

  watch: {
    async $route() {
      await this.$nuxt.refresh()
      window.scrollTo(0, 0)
    },
  },
  transition: 'home',

  async mounted() {
    this.posts = await this.$apollo.query({ query: myQuery })
    this.posts = this.posts.data.posts.nodes
    this.loading = false
}
</script>

and then comes the template :

<template>
    <section class="featured-projects">
      <div class="featured-projects__wrapper">
        <article v-for="post in posts" :key="post.id">
          <p>{{ post.id }}</p>
          <h2>{{ post.title }}</h2>
          <span>{{ post.date }}</span>
        </article>
      </div>
    </section>
  </section>
</template>

everything just works!

now, i would like to print post author name as well. i first tried this :

<span>{{ post.author }}</span>

and this actually prints this :

{
    "node": {
        "name": "max max",
        "__typename": "User"
    },
    "__typename": "NodeWithAuthorToUserConnectionEdge"
}

it totally makes sense, as author is an object with nested items in it. so according to what i’m being returned and following GraphQL API structure, to display post author name, think i should do something like this instead :

<span>{{ post.author.node.name }}</span>

and here’s the error i get, and i don’t know what to do to access what i want : Cannot read property 'node' of undefined.

1 Answers

your problem arises from reading the data before it is loaded.

depending on your js settings you should be able to use one of the following:

<span>{{ post?.author.node.name }}</span>

or <span>{{ post ? post.author.node.name : '' }}</span>


according to the Vue Apollo documentation it could also be a problem with the duplication of the query

<script>
import { myQuery } from '~/graphql/posts'

export default {
  data() {
    return {
      posts: [], // initialization
    }
  },

  apollo: {
    posts: {
      prefetch: false, // to prevent SSR
      query: myQuery,
      update: data => {
        console.log('overwrite posts with new data', data.posts)
        return data.posts
      }
    },
  }
}
</script>

further as there seem to be cases in which the author has more than one entry (perhaps co authors?) I would try to update the author rendering to the following:

<template>
    <section class="featured-projects">
      <div class="featured-projects__wrapper">
        <article v-for="post in posts" :key="post.id">
          <p>{{ post.id }}</p>
          <div v-if="Array.isArray(post.author)">
            first author is: {{ post.author[0].node.name }}
          </div>
          <div v-else-if="post.author">
           author is: {{ post.author.node.name }}
          </div>
          <div v-else="post.author">
           no author
          </div>
        </article>
      </div>
    </section>
  </section>
</template>
Related