withastro / docs

Astro documentation
https://docs.astro.build/
MIT License
1.34k stars 1.51k forks source link

⚠️ Issue: Add documentation to content collections on how to render the body when iterating through the collection #9995

Closed jjkress closed 4 days ago

jjkress commented 2 weeks ago

Problem

I want to have paginated views of posts that contain the full posts. The reason is either:

  1. You want to have a template similar to what you see in blogging software, where you have multiple pages of 10 full blog posts.
  2. You want to display short posts similar to micro.blog or Mastodon, 25 at a time.

The current documentation doesn't show how it's done and the themes and open source sites were only ever using frontmatter data when iterating through a content collection. It might be obvious to Astro pros but not when you're starting out.

Suggested solution

Just a suggestion, taken from a Discord discussion here: https://discord.com/channels/830184174198718474/1305888708834103316

---
import { getCollection, render } from 'astro:content';

const blogEntries = await getCollection('blog');

// Render all entries
const renderedEntries = await Promise.all(
  blogEntries.map(async (entry) => {
    const { Content } = await render(entry);
    return { ...entry, Content };
  })
);
---

{renderedEntries.map((entry) => (
  <article>
    <h2>{entry.data.title}</h2>
    <entry.Content />
  </article>
))}

Maybe there is a more elegant solution, but this is the best I found so far. Anyways, it would be nice to add something to be more explicit about how to achieve this. The documentation can also include the warning from kapa.ai regarding performance. But if this example would be combined with a pagination example showing one of the above use cases, it could be helpful without being overly problematic.

Mina-Sayed commented 1 week ago

Hi @jjkress,

Thank you for raising this issue and providing a detailed description along with a code example. Here is an enhanced version of your example, including pagination support:


---
import { getCollection, render } from 'astro:content';

const blogEntries = await getCollection('blog');

// Render all entries
const renderedEntries = await Promise.all(
  blogEntries.map(async (entry) => {
    const { Content } = await render(entry);
    return { ...entry, Content };
  })
);

// Pagination settings
const itemsPerPage = 10; // Adjust the number of items per page
const currentPage = Number(Astro.url.searchParams.get('page')) || 1;
const totalPages = Math.ceil(renderedEntries.length / itemsPerPage);
const paginatedEntries = renderedEntries.slice((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage);
---

{paginatedEntries.map((entry) => (
  <article>
    <h2>{entry.data.title}</h2>
    <entry.Content />
  </article>
))}

<nav>
  {Array.from({ length: totalPages }, (_, i) => (
    <a href={`?page=${i + 1}`}>{i + 1}</a>
  ))}
</nav>
sarah11918 commented 4 days ago

Hi @jjkress , and thank you @Mina-Sayed for providing a helpful example!

We do have documentation on using Astro's built-in paginate() function as well as some examples of using pagination in our Routing guide. You are correct that these do not show examples with content collections, since they were written before collections even existed!

As you might know, we are releasing Astro v5 next week, and content collections in fact has some small changes in how body content is rendered. We will be releasing brand new content collections docs, as well as a comprehensive upgrade guide with steps for converting your existing code and projects. We also have taking the Pagination reference documentation and made it easier to find on a brand new "Routing Reference" page. (We have not yet updated it, simply moved it to a new page with its own sidebar entry, so it is still the same content as our current docs.)

So, I will close this issue for now and let you examine our new docs next week! If you still have trouble implementing pagination in a way that you like, please do come and ask in our Discord and someone will be happy to help you in a support thread! Then, when you get it working the way you like, maybe you would like to suggest an improvement to the existing documentation that would have helped you!