Austinmdem
Austinmdem

Reputation: 109

Adding a 2nd dynamic template to Gatsby/NetlifyCMS correctly - Where am I going wrong?

I've added a blog page that I integrated with NetlifyCMS and it works wonderful. However, I need to have one more dynamic page on my site that displays services and each service will have its own generated template, will pretty much be very similar to the blog page in theory.

So I read around a bunch of different solutions but kept hitting a wall. What am I doing wrong here? and whats the simplest way to make this work, as I wont be adding any other dynamic pages moving forward.

Here was my gatsby-node.js when I just had the blog page and everything worked great:

const { createFilePath } = require("gatsby-source-filesystem")
exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions
  if (node.internal.type === `MarkdownRemark`) {
    const value = createFilePath({ node, getNode })
    createNodeField({
      name: `slug`,
      node,
      value,
    })
  }
}

//Blog
async function getPageData(graphql) {
  return await graphql(`
    {
      blogPosts: allMarkdownRemark {
        edges {
          node {
            fields {
              slug
            }
          }
        }
      }
    }
  `)
}

const path = require(`path`)
exports.createPages = async ({ graphql, actions }) => {
  const { data } = await getPageData(graphql)
  data.blogPosts.edges.forEach(({ node }) => {
    const { slug } = node.fields
    actions.createPage({
      path: `/articles${slug}`,
      component: path.resolve("./src/templates/articlepost.js"),
      context: {slug: slug },
    })
  })
}

So I took a stab it and tried to do the same thing but adding my services page. Here is what that ended up looking like:

gatsby-node.js

const { createFilePath } = require("gatsby-source-filesystem")
exports.onCreateNode = ({ node, actions, getNode }) => {
  const { createNodeField } = actions
  if (node.internal.type === `MarkdownRemark`) {
    const value = createFilePath({ node, getNode })
    createNodeField({
      name: `slug`,
      node,
      value,
    })
  }
}

async function getBlogData(graphql) {
  return await graphql(`
    {
      blogPosts: allMarkdownRemark(
        filter: { frontmatter: { template: { eq: "articlepost" } } }
      ) {
        edges {
          node {
            fields {
              slug
            }
          }
        }
      }
    }
  `)
}

async function getServiceData(graphql) {
  return await graphql(`
    {
      servicePosts: allMarkdownRemark(
        filter: { frontmatter: { template: { eq: "service" } } }
      ) {
        edges {
          node {
            fields {
              slug
            }
          }
        }
      }
    }
  `)
}

const path = require(`path`)
exports.createPages = async ({ graphql, actions }) => {
  const blogPage = path.resolve("./src/templates/articlepost.js")
  const servicePage = path.resolve("./src/templates/service.js")

  const { data } = await getBlogData(graphql)
  data.blogPosts.edges.forEach(({ node }) => {
    const { slug } = node.fields
    actions.createPage({
      path: `/articles${slug}`,
      component: blogPage,
      context: { slug: slug },
    })
  })

  const { serviceData } = await getServiceData(graphql)
  serviceData.servicePosts.edges.forEach(({ node }) => {
    const { slug } = node.fields
    actions.createPage({
      path: `/streaming-services${slug}`,
      component: servicePage,
      context: { slug: slug },
    })
  })
}

My blog page still works fine but I get error:

console error

As you can see I added a template type to my config.yml, that now shows in my frontmatter to separate my posts, but I think it may have just confused me a little more. Totally fine with removing the template types from frontmatter, but really need a very simple way for this to work.

Many thanks in advance!

Upvotes: 1

Views: 57

Answers (2)

xadm
xadm

Reputation: 8418

const { serviceData } = await getServiceData(graphql)

doesn't work as no serviceData in object returned from graphql( (returned by getServiceData) - it's always a data named property.

You can reuse data (if earlier data not required later) or use alias in destructuring:

const { data: serviceData } = await getServiceData(graphql)

Upvotes: 0

Ferran Buireu
Ferran Buireu

Reputation: 29315

Try aliasing your loops to avoid scoped elements.

  const { data } = await getBlogData(graphql)
  data.blogPosts.edges.forEach(({ node: post }) => {
    const { slug } = post.fields
    actions.createPage({
      path: `/articles${slug}`,
      component: blogPage,
      context: { slug: slug },
    })
  })

And:

  serviceData.servicePosts.edges.forEach(({ node: service }) => {
    const { slug } = service.fields
    actions.createPage({
      path: `/streaming-services${slug}`,
      component: servicePage,
      context: { slug: slug },
    })
  })

Basically, you are aliasing the loop item to make them unique (different from the previous loop) as post and service respectively.

I would recommend reading this article from David Walsh.

Upvotes: 1

Related Questions