Hello all,
can anybody help me to fix the error "Variable "$skip" of required type "Int!" was not provided." ?
I followed instruction below;
https://www.gatsbyjs.org/docs/adding-pagination/
I am trying to add pagination on top page of my blog, but got stuck with error "Variable "$skip" of required type "Int!" was not provided." I got also another error "Variable "$limit" of required type "Int!" was not provided.", and I guess the cause is the same.
If somebody would kindly help me to fix it, it would be highly appreciated.
And, here is my code;
src/pages/index.jsx
import React from 'react'
import Helmet from 'react-helmet'
import { graphql } from 'gatsby'
import Layout from '../components/Layout'
import Post from '../components/Post'
import Sidebar from '../components/Sidebar'
class IndexRoute extends React.Component {
render() {
const items = []
const { title, subtitle } = this.props.data.site.siteMetadata
const posts = this.props.data.allMarkdownRemark.edges
posts.forEach(post => {
items.push(<Post data={post} key={post.node.fields.slug} />)
})
return (
<Layout>
<div>
<Helmet>
<title>{title}</title>
<meta name="description" content={subtitle} />
</Helmet>
{/* commented out by kinnniku <Sidebar {...this.props} /> */}
<div className="content">
<div className="content__inner">{items}</div>
</div>
<Sidebar {...this.props} />
</div>
</Layout>
)
}
}
export default IndexRoute
debugger
export const pageQuery = graphql`
# original is below
# query IndexQuery{
query IndexQuery($skip: Int!, $limit: Int!){
site {
siteMetadata {
title
subtitle
copyright
menu {
label
path
}
author {
name
twitter
github
}
}
}
allMarkdownRemark(
# this is comment
sort: { order: DESC, fields: [frontmatter___date] }
# original is limit: 1000
limit: $limit
filter: { frontmatter: { layout: { eq: "post" }, draft: { ne: true } } , fields: { draft: { eq: false } } }
# skip is added
skip: $skip
) {
edges {
node {
fields {
slug
categorySlug
}
frontmatter {
title
featuredImage {
childImageSharp {
sizes(maxWidth: 630) {
...GatsbyImageSharpSizes
}
}
}
path
date
category
description
}
}
}
}
}
`
gatsby-node.js
const _ = require('lodash')
const Promise = require('bluebird')
const path = require('path')
const slash = require('slash')
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
return new Promise((resolve, reject) => {
const postTemplate = path.resolve('./src/templates/post-template.jsx')
const pageTemplate = path.resolve('./src/templates/page-template.jsx')
const tagTemplate = path.resolve('./src/templates/tag-template.jsx')
// Kinniku added one line below for pagination
const blogPostList = path.resolve('./src/pages/index.jsx')
const categoryTemplate = path.resolve(
'./src/templates/category-template.jsx'
)
graphql(`
{
allMarkdownRemark(
limit: 1000
filter: { frontmatter: { draft: { ne: true } } , fields: { draft: { eq: false } } }
) {
edges {
node {
fields {
slug
}
frontmatter {
tags
layout
category
}
}
}
}
}
`).then(result => {
if (result.errors) {
console.log(result.errors)
reject(result.errors)
}
// Kinniku added from here
const posts = result.data.allMarkdownRemark.edges
// Create list of posts pages
// https://www.gatsbyjs.org/docs/adding-pagination/
const postsPerPage = 10
const numPages = Math.ceil(posts.length / postsPerPage)
Array.from({ length: numPages }).forEach((_, index) => {
const withPrefix = pageNumber =>
pageNumber === 1 ? `/` : `/page/${pageNumber}`
const pageNumber = index + 1
createPage({
path: withPrefix(pageNumber),
component: blogPostList,
context: {
limit: postsPerPage,
skip: index * postsPerPage,
current: pageNumber,
total: numPages,
hasNext: pageNumber < numPages,
nextPath: withPrefix(pageNumber + 1),
hasPrev: index > 0,
prevPath: withPrefix(pageNumber - 1),
},
})
})
// Create blog posts pages.
posts.forEach((post, index) => {
const previous =
index === posts.length - 1 ? null : posts[index + 1].node
const next = index === 0 ? null : posts[index - 1].node
createPage({
path: `/post${post.node.fields.slug}`,
component: postTemplate,
context: {
slug: post.node.fields.slug,
previous,
next,
},
})
})
// kinniku added until here
_.each(result.data.allMarkdownRemark.edges, edge => {
if (_.get(edge, 'node.frontmatter.layout') === 'page') {
createPage({
path: edge.node.fields.slug,
component: slash(pageTemplate),
context: { slug: edge.node.fields.slug },
})
} else if (_.get(edge, 'node.frontmatter.layout') === 'post') {
createPage({
path: edge.node.fields.slug,
component: slash(postTemplate),
context: { slug: edge.node.fields.slug },
})
let tags = []
if (_.get(edge, 'node.frontmatter.tags')) {
tags = tags.concat(edge.node.frontmatter.tags)
}
tags = _.uniq(tags)
_.each(tags, tag => {
const tagPath = `/tags/${_.kebabCase(tag)}/`
createPage({
path: tagPath,
component: tagTemplate,
context: { tag },
})
})
let categories = []
if (_.get(edge, 'node.frontmatter.category')) {
categories = categories.concat(edge.node.frontmatter.category)
}
categories = _.uniq(categories)
_.each(categories, category => {
const categoryPath = `/categories/${_.kebabCase(category)}/`
createPage({
path: categoryPath,
component: categoryTemplate,
context: { category },
})
})
}
})
resolve()
})
})
}
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
if (node.internal.type === 'File') {
const parsedFilePath = path.parse(node.absolutePath)
const slug = `/${parsedFilePath.dir.split('---')[1]}/`
createNodeField({ node, name: 'slug', value: slug })
} else if (
node.internal.type === 'MarkdownRemark' &&
typeof node.slug === 'undefined'
) {
const fileNode = getNode(node.parent)
let slug = fileNode.fields.slug
if (typeof node.frontmatter.path !== 'undefined') {
slug = node.frontmatter.path
}
createNodeField({
node,
name: 'slug',
value: slug,
})
if (node.frontmatter.tags) {
const tagSlugs = node.frontmatter.tags.map(
tag => `/tags/${_.kebabCase(tag)}/`
)
createNodeField({ node, name: 'tagSlugs', value: tagSlugs })
}
if (typeof node.frontmatter.category !== 'undefined') {
const categorySlug = `/categories/${_.kebabCase(
node.frontmatter.category
)}/`
createNodeField({ node, name: 'categorySlug', value: categorySlug })
}
}
}
is this the repo with the error?
https://github.com/kinnikumegane/myblog
mhhh - i see there some minor differences to your posted code snippets - i have to place your snippets into your repo
i found the error:
const blogPostList = path.resolve('./src/pages/index.jsx')
your template get processed one time more than expected: when it automatic reads the pages directory - and in this case there is no context with the variables.
the solution is to move the template out of the pages directory:
const blogPostList = path.resolve('./src/templates/post-list-template.jsx')
please tell me if my solution works for you.
feel free to reopen this issue, when it is not solved
Hello @muescha
thanks a lot for your support, and your support worked !!!
What I have done is to create 'blog-list-template.jsx' file under templates directory.
And, deleted index.jsx under pages directory.
Here is revised code;
blog-list-template.jsx
import React from 'react'
import Helmet from 'react-helmet'
import { graphql } from 'gatsby'
import Layout from '../components/Layout'
import Post from '../components/Post'
import Sidebar from '../components/Sidebar'
import { Link } from 'gatsby'
class BlogList extends React.Component {
render() {
const items = []
const { title, subtitle } = this.props.data.site.siteMetadata
const posts = this.props.data.allMarkdownRemark.edges
const {
current,
total,
hasNext,
hasPrev,
nextPath,
prevPath,
} = this.props.pageContext
posts.forEach(post => {
items.push(<Post data={post} key={post.node.fields.slug} />)
})
return (
<Layout>
<div>
<Helmet>
<title>{title}</title>
<meta name="description" content={subtitle} />
</Helmet>
{/* commented out by kinnniku <Sidebar {...this.props} /> */}
<div className="content">
<div className="content__inner">{items}</div>
<ul
style={{
display: `flex`,
flexWrap: `wrap`,
justifyContent: `space-between`,
listStyle: `none`,
paddingLeft: 30,
paddingRight: 30,
}}
>
<li>
{hasPrev && (
<Link to={prevPath} rel="prev">
← Prev
</Link>
)}
</li>
<li>
{current} of {total}
</li>
<li>
{hasNext && (
<Link to={nextPath} rel="next">
Next →
</Link>
)}
</li>
</ul>
</div>
<Sidebar {...this.props} />
</div>
</Layout>
)
}
}
export default BlogList
export const pageQuery = graphql`
# original is below
# query IndexQuery{
query blogListQuery($skip: Int!, $limit: Int!){
site {
siteMetadata {
title
subtitle
copyright
menu {
label
path
}
author {
name
twitter
github
}
}
}
allMarkdownRemark(
# this is comment
sort: { order: DESC, fields: [frontmatter___date] }
# original is limit: 1000
limit: $limit
filter: { frontmatter: { layout: { eq: "post" }, draft: { ne: true } } , fields: { draft: { eq: false } } }
# skip is added
skip: $skip
) {
edges {
node {
fields {
slug
categorySlug
}
frontmatter {
title
featuredImage {
childImageSharp {
sizes(maxWidth: 630) {
...GatsbyImageSharpSizes
}
}
}
path
date
category
description
}
}
}
}
}
`
gatsby-node.js
const _ = require('lodash')
const Promise = require('bluebird')
const path = require('path')
const slash = require('slash')
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
return new Promise((resolve, reject) => {
const postTemplate = path.resolve('./src/templates/post-template.jsx')
const pageTemplate = path.resolve('./src/templates/page-template.jsx')
const tagTemplate = path.resolve('./src/templates/tag-template.jsx')
// Kinniku added one line below for paginationmeikakun
const blogPostList = path.resolve('./src/templates/blog-list-template.jsx')
const categoryTemplate = path.resolve('./src/templates/category-template.jsx')
graphql(`
{
allMarkdownRemark(
limit: 1000
filter: { frontmatter: { draft: { ne: true } } , fields: { draft: { eq: false } } }
) {
edges {
node {
fields {
slug
}
frontmatter {
tags
layout
category
}
}
}
}
}
`).then(result => {
if (result.errors) {
console.log(result.errors)
reject(result.errors)
}
// Kinniku added from here
const posts = result.data.allMarkdownRemark.edges
// following codes are added by Kinniku
// because posts.length returns the number of "posts" plus "pages", posts.length can not be used to calculate number of pages
// therefore, we need to use "count" which counts only the number of items includes the link '/posts'
let count = 0
posts.forEach((post) => {
if(post.node.fields.slug.includes('/posts')){
count = count + 1
} else{
}
})
// Create list of posts pages
// https://www.gatsbyjs.org/docs/adding-pagination/
const postsPerPage = 6
// posts.length was replaced with count
let numPages = Math.ceil(count / postsPerPage)
Array.from({ length: numPages }).forEach((_, index) => {
const withPrefix = pageNumber => pageNumber === 1 ? `/` : `/page/${pageNumber}`
const pageNumber = index + 1
createPage({
path: withPrefix(pageNumber),
component: blogPostList,
context: {
limit: postsPerPage,
skip: index * postsPerPage,
current: pageNumber,
total: numPages,
hasNext: pageNumber < numPages,
nextPath: withPrefix(pageNumber + 1),
hasPrev: index > 0,
prevPath: withPrefix(pageNumber - 1),
},
})
})
// Create blog posts pages.
posts.forEach((post, index) => {
const previous = index === posts.length - 1 ? null : posts[index + 1].node
const next = index === 0 ? null : posts[index - 1].node
createPage({
path: `/post${post.node.fields.slug}`,
component: postTemplate,
context: {
slug: post.node.fields.slug,
previous,
next,
},
})
})
// kinniku added until here
_.each(result.data.allMarkdownRemark.edges, edge => {
if (_.get(edge, 'node.frontmatter.layout') === 'page') {
createPage({
path: edge.node.fields.slug,
component: slash(pageTemplate),
context: { slug: edge.node.fields.slug },
})
} else if (_.get(edge, 'node.frontmatter.layout') === 'post') {
createPage({
path: edge.node.fields.slug,
component: slash(postTemplate),
context: { slug: edge.node.fields.slug },
})
let tags = []
if (_.get(edge, 'node.frontmatter.tags')) {
tags = tags.concat(edge.node.frontmatter.tags)
}
tags = _.uniq(tags)
_.each(tags, tag => {
const tagPath = `/tags/${_.kebabCase(tag)}/`
createPage({
path: tagPath,
component: tagTemplate,
context: { tag },
})
})
let categories = []
if (_.get(edge, 'node.frontmatter.category')) {
categories = categories.concat(edge.node.frontmatter.category)
}
categories = _.uniq(categories)
_.each(categories, category => {
const categoryPath = `/categories/${_.kebabCase(category)}/`
createPage({
path: categoryPath,
component: categoryTemplate,
context: { category },
})
})
}
})
resolve()
})
})
}
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
if (node.internal.type === 'File') {
const parsedFilePath = path.parse(node.absolutePath)
const slug = `/${parsedFilePath.dir.split('---')[1]}/`
createNodeField({ node, name: 'slug', value: slug })
} else if (
node.internal.type === 'MarkdownRemark' &&
typeof node.slug === 'undefined'
) {
const fileNode = getNode(node.parent)
let slug = fileNode.fields.slug
if (typeof node.frontmatter.path !== 'undefined') {
slug = node.frontmatter.path
}
createNodeField({
node,
name: 'slug',
value: slug,
})
if (node.frontmatter.tags) {
const tagSlugs = node.frontmatter.tags.map(
tag => `/tags/${_.kebabCase(tag)}/`
)
createNodeField({ node, name: 'tagSlugs', value: tagSlugs })
}
if (typeof node.frontmatter.category !== 'undefined') {
const categorySlug = `/categories/${_.kebabCase(
node.frontmatter.category
)}/`
createNodeField({ node, name: 'categorySlug', value: categorySlug })
}
}
}
great.
thank you for the status update.
i added a feature request to have better hints:
Feature Request: better error message if templates in /pages/ and get an errorYep, I saw it, and thanks for sharing your expertise !
I could learn how documentation should look like )