onTheInternet
onTheInternet

Reputation: 7253

Using map on returned graphql query is making known members undefined

I'm using Gatsbyjs to build a blog and I can't use the onCreatePage API to pass data from my graphql query into page templates.

My query grabs data from Kentico Cloud and it looks like this.

{
    allKenticoCloudTypeBlogPost{
        edges{
            node{
                contentItems{
                    elements{
                        url_slug{
                            value
                        }
                    }
                }
            }
        }
    }
}

This is a valid query and it returns data that looks like this.

Graphql returned query

The problem comes in my gatsby-node.js file where I want to utilize this query to build out pages using my predefined template.

Specifically in the createPage method which looks like this.

result.data.allKenticoCloudTypeBlogPost.edges.map(({node}) => {        
    createPage({
        path: `${node.contentItems.elements.url_slug.value}`,
        component: path.resolve(`./src/templates/blog-post.js`),
        context: {
            slug: node.contentItems.elements.url_slug.value,
        }
    })

});

The error that displays is the following.

TypeError: Cannot read property 'url_slug' of undefined

  • gatsby-node.js:31 result.data.allKenticoCloudTypeBlogPost.edges.map C:/Users/xxxx/Desktop/Marketing Repos/xxxx/gatsby-node.js:31:57

I decided to investigate doing a console.table on node.contentItems, as it appears as though the elements part is where it gets tripped up.

The result of console.table(node.contentItems) just before the createPage method is this.

table

It appears that node.contentItems has a member called url_slug rather than the elements member that I expected.

I thought I could then solve my problem by updating my createPage method call like so.

result.data.allKenticoCloudTypeBlogPost.edges.map(({node}) => {
    console.table(node.contentItems);

    createPage({
        path: `${node.contentItems.url_slug.value}`,
        component: path.resolve(`./src/templates/blog-post.js`),
        context: {
            slug: node.contentItems.url_slug.value,
        }
    })

});

But then I get an error saying

TypeError: Cannot read property 'value' of undefined.

I truly don't understand how I can do a table log and see the url_slug member, but then when I try to access it, it says that it's undefined. All while I know that my query is correct because I can run it in graphiQL and get back the exact data I expect.

Any help would be appreciated. Thank you.

Upvotes: 0

Views: 1518

Answers (2)

Derek Nguyen
Derek Nguyen

Reputation: 11577

In your query result, node.contentItems is an array, even though you're trying to access it as if it's an object:

path: `${node.contentItems.elements.url_slug.value}`,
                           ^^^^^^^^

console.log(contentItems) // [ { elements: {...} }, { elements: {...} }, ... ]

I think your confusion probably stems from the way console.table display data. It's confusing if you don't already know the shape of your data. Your screenshot says, this object has 4 properties with index 0 -> 3 (so likely an array), each has one property called elements (listed on table header), which is an object with the only property url_slug.


I'm not familiar with KenticoCloud, but maybe your posts are nested in contentItems, in which case you should loop over it:

result.data.allKenticoCloudTypeBlogPost.edges.map(({node}) => {        
  node.contentItems.forEach(({ elements }) => {
    createPage({
      path: elements.url_slug.value,
      context: { slug: elements.url_slug.value },
      component: ...
    })

  })
});

Upvotes: 1

Alyssa Hope
Alyssa Hope

Reputation: 11

Is there a reason you are wrapping node with curly brackets in your map argument?

You might have already tried this, but my first intuition would be to do this instead:

result.data.allKenticoCloudTypeBlogPost.edges.map(node => {  

    console.log(node.contentItems)
    createPage({
        path: `${node.contentItems.elements.url_slug.value}`,
        component: path.resolve(`./src/templates/blog-post.js`),
        context: {
            slug: node.contentItems.elements.url_slug.value,
        }
    })

});

Upvotes: 0

Related Questions