Using Modular fields with Gatsby

Having a bit of a tough time wrapping my head around Modular fields and getting that data on my Gatsby site.

Iā€™ve set up a Modular Content block as seen on this page (Modular content fields ā€” DatoCMS) and I can successfully query the data in my graphql playground like:

          content {
              ... on DatoCmsBlogPostTextBlock {
                  text
              }
          }

, but including _modelApiKey throws this error.
Cannot query field ā€œ_modelApiKeyā€ on type ā€œDatoCmsBlogPostTextBlockā€.

A similar page (Modular content fields ā€” DatoCMS ā†’ BTW, what are the other SSG weā€™re talking about?) has mention of a dato.config.js file. I donā€™t have that file so maybe thatā€™s the cause for error?

In my work.js template (using the gastby/datocms template ā†’ https://www.gatsbyjs.org/starters/datocms/gatsby-portfolio/) Iā€™ve added the query above and Iā€™m trying to get my data on the website like:

{data.datoCmsWork.content.text}

Now, I think the API key basically IDs the proper field and the way to get it on the site probably involves a .map() to render out whateverā€™s in the modular block.

Iā€™ve been looking but canā€™t find documentation on this and was hoping to get some help and maybe help others looking for this info too.

This is my first post here. Fairly new in the DatoCMS/Gatsby world. Hi all!
Let me know if thereā€™s any more details I can provide.
Thanks! :slight_smile:

hello @consolecmnd and welcome to Community :slight_smile:

to get the API key of a modular content you can have a look here: GitHub - datocms/gatsby-source-datocms: Official GatsbyJS source plugin to pull content from DatoCMS

you need to extract

model { apiKey }

And to get some usage examples you can start from these:

Let me know if you need more info!

Cheers

Hi Mat, thanks for providing the links.

My site is based off of the Gatsby Portfolio and I looked through the code of the snipcart-gatsby-demo and Iā€™m not seeing any usage examples of the model { apiKey }.

Trying again the example from https://github.com/datocms/gatsby-source-datocms#modular-content-fields

My query looks like

export const query = graphql`
  query WorkQuery($slug: String!) {
    datoCmsWork(slug: { eq: $slug }) {
      content {
        ...on DatoCmsBlogPostTextBlock {
          model { apiKey }
          text
        }
      }
    }
  }

And in the same file, Iā€™m trying to get output with:

     {
       data.datoCmsWork.content.map((block) => (
         <div key={block.id}>
           {
             block.model.apiKey === 'text' &&
               <div>{block.text}</div>
           }
         </div>
       ))
     }

Results in an error reading:
TypeError: Cannot read property 'apiKey' of undefined

error --> <div key={block.id}>

To try to get the apiKey from GraphQL I added the following to the layout.js file.

     allDatoCmsModel {
       edges {
         node {
           apiKey
         }
       }
     }

Added to the LayoutQuery query to try and create a global variable but not getting any output from my populated Modular fields.

I can see my data in the GraphQL Playground when I run the queries, but Iā€™m having trouble translating that to the site.

In the future could the base DatoCMS/Gatsby portfolio starter template be possibly updated to include an example of Modular content in use?

Sorry for the long post.

because you have two different blocks that can be part of the content, which means that you are getting two objects back, one of which doesnā€™t have {model {apiKey}}

this is your content now:

"content": [
            {
              "model": {
                "apiKey": "blog_post_text_block"
              },
              "text": "Lorum Ipsum Lorum Ipsum Lorum Ipsum Lorum Ipsum Lorum Ipsum Lorum Ipsum ",
              "__typename": "DatoCmsBlogPostTextBlock"
            },
            {
              "__typename": "DatoCmsBlogPostQuoteBlock"
            }
          ]

does that explain what I mean? You should add one fragment for each type of block to handle all the options, like this:

content {
        ... on DatoCmsBlogPostTextBlock {
          model {
            apiKey
          }
          text
        }
        ... on  DatoCmsBlogPostQuoteBlock{
          model {
            apiKey
          }
        }
      }

Hi @mat_jack1, thanks again for the advice. It was enough for me to get things rolling.

I think the thing I was hung up on was that the Model ID provided in the CMS is actually the apiKey. Not sure why, but I didnā€™t see the connection there.

Once I saw that matching up in the console log it wasnā€™t much trouble for the rest to follow.

If anyone finds this in the future, hereā€™s roughly what you can do.

  query WorkQuery($slug: String!) {
    datoCmsWork(slug: { eq: $slug }) {
      content {
        ...on DatoCmsBlogPostTextBlock {
          model { apiKey }
          text
        }
        ...on DatoCmsBlogPostQuoteBlock {
          model { apiKey }
          quote
          author
        }
      }
    }
  }

Then to output:

<div>
  {
    data.datoCmsWork.content.map((block) => (
      <div key={block.id}>
        {
          block.model.apiKey === 'blog_post_text_block' &&
            <div>{block.text}</div>
        }
        {
          block.model.apiKey === 'blog_post_quote_block' &&
          <div>{block.quote}<br/>{block.author}</div>
        }
      </div>
    ))
  }
</div>

Cheers and thanks again!

1 Like

Hey @consolecmnd,

Iā€™m also trying to use modular content fields for my website and Iā€™ve tun into a slightly different issue.

I see inside your content field you have a modular field titled text. How do you use this field? Do you just use it for paragraph text and nothing more of does it contain all kinds of headings, links etc?

Iā€™m trying to use a modular text field to parse markdown but because the graphQL endpoint only gives a string, my markdown doesnā€™t parse.

Any help would be my holy appreciated.

Hey @consolecmnd ,

I was wondering if anyone knows how to get modular content to be included in the statically generated build script? The modular content which loops through and gets rendered by the correct component based on the apiKey for some reason does not get included in my builds.