Last three Blog Articles published - Help crafting the query

Hi I'm wanting to extend my app to include a new slice 'RecentPosts'.

How would I query my posts content type to extract just the most recent three posts that have been published?

Once I know the basics of this, this will help me with many different similar queries I want to do.

Thx

Hello! Are you using GraphQL or the REST API?

I'm using just the REST API.

You need to query all documents with the type you want, and order by last_publication_date:

You can try it out on https://your-repository-url.prismic.io/api

Ok thankyou.

  1. How do I then limit the returned results to just the first three (3)?

  2. Related, my mental model around how to get values showing up in vue seems to be broken.. maybe you can clarify..

Here is the js in my RecentArticles slice below, but it gives me the warning:

Vue warn]: Property or method "posts" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.

What am I missing?

export default {
  props: {
    slice: {
      type: Object,
      required: true,
      default() {
        return {}
      }
    }
  },
  
  async asyncData({ $prismic, error }) {
    try{
      // Query to get posts content to preview
      const PostItems = await $prismic.api.query(
        $prismic.predicates.at('document.type', 'post'),
        { pageSize : 3, page : 1, orderings : '[my.post.date desc]' }
      )
      const animals = ["cat", "dog", "pig"]
      
      const recentPosts = PostItems.slice(0,2)
      return {
        posts: PostItems,
        animals: animals,
        recent_posts: recentPosts
      }
    } catch (e) {
      // Returns error page
      error({ statusCode: 404, message: 'Page not found' })
    }
  },
}

As you can see Im attempting to return 3 results two different ways (either using the pageSize or by running .slice)

Currently NONE of these values is showing up when I use the Vue insector and also I have no idea why my slices are all named in the Vue inspector and how to change this to match the slice name.

As you can see, no mention of my return values posts/animals/recent_posts.. Confused

I'd do that client-side, with .slice(0, 3) or something.

asyncData doesn't work in components. You'll have to use data/mounted like Vue, or else fetch that data in the actual page, and pass it through as another prop.

Ok I'm keen to stick with Nuxt & Prismic and keep things simple by passing it in as a prop.

In my main page being posts/_uid.vue I have this:

async asyncData({ $prismic, params, error }) {
  try {
    const content_type = 'home'
    const document = (await $prismic.api.getSingle(content_type)).data
    return {
        doc: document,
    }
  } catch (e) {
    error({ statusCode: 404, message: 'Page not found' })
  }
}

I'd like to also look up recent posts and make that available to child slices/components..

I'm getting stuck in your documentation here..

Provides..

this.$prismic.client.query(
  this.$prismic.Predicates.at('document.type', 'blog_post'),
  { orderings : '[my.blog_post.date desc]' }
).then((response) => {
  // response is the response object, response.results holds the documents
})

But how do I get the above into something like this that I can work with..

Desired changes to posts/_uid.vue ....

async asyncData({ $prismic, params, error }) {
  try {
    const content_type = 'home'
    const document = (await $prismic.api.getSingle(content_type)).data
    const posts = .... // <==== what goes here?
    const recentPosts = posts.slice(0,3)   // also without generating any errors that might occur here

    return {
        doc: document,
        recent_posts = recentPosts   // So that in children slices/components I can do v-for posts in recent_posts
    }
  } catch (e) {
    error({ statusCode: 404, message: 'Page not found' })
  }
}

Thank you

Something like this:

<script>
export default {
  async asyncData ({ $prismic, params, error }) {
    try {
      const document = (await $prismic.api.getByUID('page', params.uid)).data
      const posts = await $prismic.api.query(
        $prismic.predicates.at('document.type', 'blog_post'),
        { orderings: '[my.blog_post.date desc]' }
      )
  
      return {
        document,
        posts: posts.results.slice(0, 3),
      }
    } catch (err) {
      error({ statusCode: 404, message: 'Page not found' })
    }
  }
}
</script>

Thanks @marcellothearcane.
I'm feeling pretty silly now, I feel like Im missing something really obvious.

I added your code and now I'm getting this error, below.
I've followed the link and read about it in a bunch of articles and it's not coming together for me what Im doing wrong.

This is the same error I had at the start and it refers me to Vue Reactivity and suggests possibly creating an empty field in 'data'. But as Im using Nuxt there's generally nothing else referring to 'data', so I feel this is the wrong direction. Also I note your earlier comment " asyncData doesn't work in components." but am still confused as to how to implement this.

Appreciate any further insight.

Thnx

[Vue warn]: Property or method "posts" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.

found in

---> <RelatedArticles> at components/RelatedArticles.vue
       <Post> at pages/posts/_uid.vue
         <Nuxt>
           <Layouts/default.vue> at layouts/default.vue
             <Root>

Could you share your repository?

It's a private repo but happy to give you access.
What's your github username?

Great, thanks! It's https://github.com/marcellothearcane

Ok @marcellothearcane I've just given you access to the repo.
My github username is evolve2k so you can identify it.

1 Like

Thanks so much for fixing this @marcellothearcane.
Since it was inside private code, I've extracted relevant parts of the code here for anyone seeking to do the same.

The key parts were.

  1. Create a data section with an empty "articles" array
  2. Use async fetch to bring in the data and populate the "articles" array
  3. Pass articles array into <article-card> with v-for defining 'article'
  4. Within ArticleCard.vue create a prop to bring in 'article'

#components/RecentArticles.vue

<template>
  <section
    name="recent-articles">
      <article-card
        v-for="(article, index) of articles"
        :key="index"
        :article="article"
      />
    </div>
  </section>
</template>
<script>
import SliceZone from "vue-slicezone";
export default {
  name: "recent-articles",
  head() {
    return {
      title: "Brave Energy Systems",
    };
  },
  data() {
    return {
      articles: [],
    };
  },
  async fetch() {
    // See fetch docs: https://nuxtjs.org/docs/2.x/components-glossary/pages-fetch
    const prismic = this.$nuxt.context.$prismic;
    const { results } = await prismic.api.query(
      prismic.predicates.at("document.type", "post")
    );
    const latestPosts = results.slice(0, 3);
    this.articles.push(...latestPosts);
  },
};
</script>

And here's /components/ArticleCards.vue

<template>
  <nuxt-link
    :to="`/posts/${article.uid}`"
    class="no-underline p-0 m-0 hover:no-underline hover:text-current"
  >
    <div
      name="article cards"
      class="snap-align-center h-82 w-68 flex flex-col justify-between rounded-xl bg-white shadow-card xs:h-104 lg:h-118 lg:w-77"
    >
      <div>
        <h3 class="px-6 pt-6 text-sm-h3 leading-sm-h3 xs:px-7">
          {{ article.data.title[0].text }}
        </h3>
        <small class="px-6 text-tiny font-semibold italic xs:px-7 md:pt-3">
          {{ article.data.author[0].text }}
        </small>
      </div>
      <prismic-image
        :field="article.data.optional_image"
        class="rounded-b-xl h-27 w-full xs:h-36 lg:h-40"
      />
    </div>
  </nuxt-link>
</template>

<script>
export default {
  name: "article-card",
  props: {
    article: {
      required: true,
    },
  },
};
</script>
1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.