Displaying all modular blocks in GatsbyJS

Hi folks.
Iā€™m getting done my first job with Gatsby and DatoCMS, and I thought I could go step forward. My client has products, actually few of them. So I created model for him and I used modular content so he could add new products in the future. Like you are probably guessing, Iā€™m trying to map product via graphQL query and display it to the component in Gatsby.

But first things first.

My model looks like that:

And my query:

query SingleProductQuery {
      allDatoCmsProduct {
          edges {
              node {
                  product {
                      id
                      nameOfProduct
                      descriptionOfProduct
                      imageOfProduct {
                          fluid {
                              ...GatsbyDatoCmsFluid_tracedSVG
                          }
                      }
                  }
              }
          }
      }
  }

And my component in Gatsby should iterate through each product with that markup:

 <StyledProduct>
  {
    data.allDatoCmsProduct.edges.map(({ node: product }) => (
      <div key={product.id}>
        <Image fluid={product.imageOfProduct.fluid} />
        <ProductName>
          <h2>{product.nameOfProduct}</h2>
        </ProductName>
        <ProductDesc>
        <p>{product.descriptionOfProduct}</p>
        </ProductDesc>
        <ButtonWrapper>
        <Button>
        <Link to="/">
        read <b>mor</b>
        </Link>
        </Button>
        </ButtonWrapper>
      </div>
    ))
  }
</StyledProduct> 

But I must do something wrong, because itā€™s not working. I tried many configurations but Gatsby is always telling me, that ā€œTypeError: Cannot read property id of undefinedā€. I tried to recreate code from Creating a static e-commerce website with Snipcart, GatsbyJS and DatoCMS tutorial, but since the query looks different, I failed. I really hope you can help me guys. Thanks in advance!

hey @leeszczuu looking at your schema, looks like you need to iterate one level deeper. You should iterate again on your product as that is the modular content inside the product model. You might want to rename one of the two as I think itā€™s a bit confusing in your case.

But to clarify how the data is structured you should check in your local GraphiQL: http://localhost:8000/___graphql if you try running your query there youā€™ll see that product itself is an array.

Let me know if I can help you more here.

Thanks Mat for respond. I realized that I missunderstood modular blocks concept and I refcatored my ā€œproductsā€ into simple model with many fields. Iā€™ve created template file for each product page but I have problems with generating page for each record in Product model.
My gatsby-node files looks like this, which seems fine for me:

const path = require('path')

exports.createPages = ({ actions, graphql }) => {
  const { createPage } = actions

  const template = path.resolve(`src/layouts/product.js`)

  return graphql(`
      query MyQuerySingleProduct {
        allDatoCmsProduct {
          edges {
            node {
              slug
            }
          }
        }
      }
  `).then(result => {
    if (result.errors) {
      return Promise.reject(result.errors)
    }

    result.data.allDatoCmsProduct.edges.forEach(({ node }) => {
      console.log(node);
      createPage({
        path: `/produkt/${node.slug}`,
        component: template,
        context: {
          slug: node.slug
        }
      })
    })
  })
}

but I got this error in terminal when run gatsby develop:

 ERROR #11321  PLUGIN

"gatsby-source-datocms" threw an error while running the sourceNodes lifecycle:

invalid json response body at https://site-api.datocms.com/site?include=item_types%2Citem_types.fields reason: Unexpected token < in JSON at position 0



  FetchError: invalid json response body at https://site-api.datocms.com/site?include=item_types%2Citem_types.fields reason: Unexpec  ted token < in JSON at position 0

  - body.js:48
    [gatsby-classic-theme]/[isomorphic-fetch]/[node-fetch]/lib/body.js:48:31

  - next_tick.js:68 process._tickCallback
    internal/process/next_tick.js:68:7

Not sure if itā€™s something with Dato or with my code. It would be much appreciate if you could take a look at it :slight_smile:

Update:

I added
const { createFilePath } = require(gatsby-source-filesystem)
at the top of my gatsby-node file and it created pages for each product. Thing is, that all these pages are pulling data from 1 record only. I tried to change datoCmsProduct to allDatoCmsProduct and map it to all nodes but then I get ā€œcannot read property of nullā€ error highlighting my
<h1{data.allDatoCmsProduct.edges.node.name</h1>
So I reverted this to datoCmsProduct

My product template pages I mentioned above look like this:

import React from 'react';
import { graphql, useStaticQuery } from 'gatsby';

const ProductPage = () => {

  const data = useStaticQuery(graphql`
      query SingleProductQuery {
          datoCmsProduct(id: {eq: "DatoCmsProduct-4695093-en"}) {
              name
          }
      }
  `);

  return (
    <Layout>
      <SectionHero>
          <h1>{data.datoCmsProduct.name}</h1>
      </SectionHero>
      
    </Layout>
  )}

export default ProductPage;

My question is how should I construct this ProductPage function to iterate through all nodes within allDatoCmsProduct to make it display all my products content on each page generated?
Thanks in advance!

have a look at our example project on how we fetch content from our pages: https://github.com/datocms/gatsby-portfolio/blob/master/src/templates/work.js

does this help?

I figured it out this morning and this is exactly how I did that :slight_smile: Just forgot to mention.
Peace

1 Like