1

I want to map the frontmatter subitems in Gatsby template. The infobox has sub-items and I want to map the infobox as they will change per article. Some articles may have 3 others may have 10. Some articles will have date and fullName others will have different, for example, address, date of birth etc

Instead of


 {
              infoboxItems.map((item, index) => {

                <li key={index}>
                {item.fullName}
                {item.date}
                {item.this}
                {item.something_here}
                 </li>

              })
            }

I want the infobox to return items without specifying the fullname, date, this and something_here

Should return anything that is the Mdx file

differentSubItem: anything
AnotherSubItem: anything
thisSubItem: that

Mdx file 1

---
title: this is is the title
description: this is sthe description of the article here. 
featuredImage: ../../src/images/myimage.png
infobox:
- date: somedate 
- something_here: nothing
- this: that
---

#This is a test article
Hi this is a test article

##this is a title
this is some text

###this is h3
this is some text

Mdx file 2

---
title: another title comes
description: this a SEO Description for title 2 
featuredImage: ../../src/images/myimage2.png
infobox:
- dateOfBirth: somedate 
- addressOfPublisher: 123 Main Street
- phoneNumber: 000 000 0000
---

#This is a test article
Hi this is a test article

##this is a title
this is some text

###this is h3
this is some text

The template file {mdx.slug}.jsx

import React from "react"
import { graphql } from "gatsby"
import { GatsbyImage, getImage } from "gatsby-plugin-image"
import { MDXRenderer } from 'gatsby-plugin-mdx'

const EnglishArticleTemplate = ({ data }) => {

  // console.log("all data")
  // console.log(data)



  const article = data.mdx //all articles

  // console.log("article")
  // console.log(article)

  const featuredImage = getImage(article.frontmatter.featuredImage)
  const infoboxItems = article.frontmatter.infobox

  // console.log("infobox items")
  // console.log(infoboxItems)
  

  return (
    <div>
      <h1>{article.frontmatter.title}</h1>
      <GatsbyImage image={featuredImage} />
      <MDXRenderer>
          {article.body}
            </MDXRenderer>

            {
              infoboxItems.map((item, index) => {

                // <li key={index}>
                //   {item.fullName}
                // </li>

              })
            }
    
    </div>
  )
}


export const query = graphql`
query GetPostById ($id: String) {
  mdx (id: {eq: $id}) {
    frontmatter {
      featuredImage {
        childImageSharp {
          gatsbyImageData(
            transformOptions: {cropFocus: CENTER}
            placeholder: BLURRED
            formats: WEBP
            blurredOptions: {width: 100}
          )
        }
      }
      title
      infobox {
        date
        fullName
        something_here
        this
        dateOfBirth
        addressOfPublisher
        phoneNumber
      }
    }
    id
    body
    slug
  }
}
`

export default EnglishArticleTemplate

mardag
  • 21
  • 1
  • 6

1 Answers1

2

First of all, your map loop won't work because you are not returning anything. Change it to:

{
  infoboxItems.map((item, index) => {
    return <li key={index}>{item.fullName}</li>;
  });
}

Regarding your question, you can simply use the Object.keys or Object.values methods to get an array of keys/values from an object (infobox) to loop without knowing them beforehand, so without accessing each position specifically:

Object.keys(article.frontmatter.infobox).forEach((key, index)) => {
  console.log(`${key}: ${article.frontmatter.infobox[key]}`);
}

Applied to your JSX, something like:

{
  Object.keys(article.frontmatter.infobox).map((key) => {
    return <li key={key}>{article.frontmatter.infobox[key]}</li>;
  });
}

Note the change of forEach instead of map loop.

Ferran Buireu
  • 28,630
  • 6
  • 39
  • 67