11ty / eleventy

A simpler site generator. Transforms a directory of templates (of varying types) into HTML.
https://www.11ty.dev/
MIT License
17.1k stars 494 forks source link

Limit the output of a Collection #1368

Closed GrantSmithDoddle closed 4 years ago

GrantSmithDoddle commented 4 years ago

I am trying to limit the output of a collection. For example, I have a products collection and I only wish for five of these products to display once rendered.

This is further to Issues 503.

I am trying to achieve the same as Issue 503, using that example I have the below. I am using nunjucks which I now realise could be the reason why this isn't working.

{% assign allproductposts = collections.products limit: 2 -%}
{% for product in allproductposts -%}
{% include "partials/product_card.html" -%}
{% endfor -%}

With the code above I just get an error saying, unknown block tag: assign.

Am I missing a filter or extension of some kind? Would really appreciate some guidance.

All variations I have tried based on Issue 503 result in the same error?

binyamin commented 4 years ago

I am using nunjucks which I now realise could be the reason why this isn't working.

Correct. Assign is liquid syntax.

pdehaan commented 4 years ago

Posted some solutions in https://github.com/11ty/eleventy/issues/503#issuecomment-675634733

I can upload my test repo to github when I get back to my laptop, but I was assuming you were using liquidjs. I can try and do it in nunjucks too, if that’s what you’re using (based on your comments above).

GrantSmithDoddle commented 4 years ago

I am definitely using nunjucks, sorry, only occurred to me later that this is would be an issue.

pdehaan commented 4 years ago

We can possibly use nunjucks’ https://mozilla.github.io/nunjucks/templating.html#slice filter

GrantSmithDoddle commented 4 years ago

Ah! Almost!

{% for product in collections.products | slice(3) -%}
  {% include "partials/product_card.html" -%}
{% endfor -%}

The above does indeed limit my outputted products to 3. However, all content within my product_card.html is blank. One example being, within the card there is a <h2>{{ product.data.title }}</h2> which outputs to <h2></h2>.

I also moved the content of partials/product_card.html to where my {% include "partials/product_card.html" -%} is. But it made no difference.

pdehaan commented 4 years ago

Sorry, I haven't looked at the Nunjucks slice() filter in a while. It actually seems to return an array of sub-arrays in this case.

"Slice an iterator and return a list of lists containing those items"

Probably not what we want here, but I think easily solved by a custom Nunjucks filter in our .eleventy.js config file:

module.exports = eleventyConfig => {
  eleventyConfig.addNunjucksFilter("limit", (arr, limit) => arr.slice(0, limit));

  return {
    dir: {
      input: "src",
      output: "www"
    }
  }
};

And then we can use the custom "limit" filter in Nunjucks like so:

---
title: Products (Nunjucks)
---

<h1>{{ title }}</h1>

<h2>Option 1: <code>set..limit*</code></h2>
{% set allproductposts = collections.products_nunjucks | limit(2) %}
<ul>
{% for products in allproductposts %}
  <li>{{ products.data.title }}</li>
{% endfor %}
</ul>
GrantSmithDoddle commented 4 years ago

Fantastic, all working as I wanted!

Thank you all for the help and your patience.

huphtur commented 4 years ago

You can also use Nunjucks "special variables" inside a loop:

{% for post in collections.post | reverse %}
  {% if loop.index0 < 5 %}
    ...
  {% endif %}
{% endfor %}
binyamin commented 4 years ago

@granttransition If you're satisfied with the solutions, would you mind if I close the issue?

GrantSmithDoddle commented 4 years ago

Sorry, now closed

isralduke commented 1 year ago

This was helpful, thank you

Kairat619 commented 8 months ago

You can also use Nunjucks "special variables" inside a loop:

{% for post in collections.post | reverse %}
  {% if loop.index0 < 5 %}
    ...
  {% endif %}
{% endfor %}

Thank you so much! it works!!!