Nunjucks: Loop through first 5 items in for loop

6.3k views Asked by At

New to Nunjucks and have a similar problem to here but I couldn't get my code to work. I'm trying to loop through the first 5 items in a Nunjucks loop of 14 items. So far I've found that the range function should be able to accomplish this but can't get the syntax right. It seems like I'm pointing to the index incorrectly.

My code to get all 14 items is:

    {% for images in index %}
      <div class="spacer col-md-2 col-sm-6">
      </div>
      <div class="yellp-img col-md-2 col-sm-6">
        <img src="/uploads/images/{{ images.image.filename }}" />
      </div>
    {% endfor %}

This prints all 14 images in index. I could also print 14 images using the following:

    {% for images in range(0, index.length) -%}
      <div class="spacer col-md-2 col-sm-6">
      </div>
      <div class="yellp-img col-md-2 col-sm-6">
        <img src="/uploads/images/{{ images.image.filename }}" />
      </div>
    {%- endfor %}

The problem is then all the images are broken (printed without the filename in src url) as follows:

<img src="/uploads/images/" />

This is probably obvious but I can't figure out how to limit how many images print with the data from the filename.


UPDATE (responding to Aikon's comment below): Image data is stored as JSON (loaded through Express/Node using Keystonejs CMS). A console log of the data loaded from Express is as follows:

    images={ _id: 59acf4ef822f172bc92ceaf9,
  __v: 0,
  image: 
   { filename: 'b8LMOFEstFE0K8eW.png',
     size: 7070,
     mimetype: 'image/png' } },{ _id: 59acf58d822f172bc92ceafa,
  __v: 0,
  image: 
   { filename: 'SZSJDneW0l3DumOz.png',
     size: 10070,
     mimetype: 'image/png' } },{ _id: 59acf6a4822f172bc92ceafb,
  __v: 0,
  image: 
   { filename: 'CLlGDaqZv6gBDt1B.png',
     size: 9235,
     mimetype: 'image/png' } },{ _id: 59acf751822f172bc92ceafc,
  __v: 0,
  image: 
   { filename: 'x-K9if9xSIaDFD-0.png',
     size: 8670,
     mimetype: 'image/png' } },{ _id: 59acf7ac822f172bc92ceafd,
  __v: 0,
  image: 
   { filename: '4dTpPFWD3nqCKqcr.png',
     size: 11181,
     mimetype: 'image/png' }

That results from the following code in my keystone view to load the image data via Express/Node from MongoDB:

    // Load the current post
view.on('init', function(next) {

    var images = keystone.list('ImageUpload').model.find()
        .sort('-createdAt')
        .limit(5)
        .populate('images');

    images.exec(function(err, result) {
        if (result !== null) {
            var images = result;
            console.log('images=' + images);
        } else {
            console.log('404!!!');
            return res.status(404).render('errors/404');
        }
        next(err);
    });

});

// Load All Images
view.query('index', keystone.list('ImageUpload').model.find());

// Render the view
view.render('index');

So index is referring to the current view, not the database model. Hopefully that clarifies.

2

There are 2 answers

1
Aikon Mogwai On BEST ANSWER
// Nunjucks
{% set length = images.length if images.length < 13 else 13 %} 
{% for i in range(0, length) %}
<img src="/uploads/images/{{images[i].image.filename}}" />
{% endfor %}

// Node.js + Nunjucks
var nunjucks  = require('nunjucks');
var env = nunjucks.configure();

var images = [{ 
    _id: '59acf4ef822f172bc92ceaf9',
    __v: 0,
    image: { 
        filename: 'b8LMOFEstFE0K8eW.png',
        size: 7070,
        mimetype: 'image/png' }
    }, { 
    _id: '59acf58d822f172bc92ceafa',
    __v: 0,
    image: { 
        filename: 'SZSJDneW0l3DumOz.png',
        size: 10070,
        mimetype: 'image/png' } 
    },{ 
    _id: '59acf6a4822f172bc92ceafb',
    __v: 0,
    image: { 
        filename: 'CLlGDaqZv6gBDt1B.png',
        size: 9235,
        mimetype: 'image/png' } 
    }];

// You can prepare data before pass it to Nunjucks
// var filenames = images.map((e) => e.image.filename);

res = nunjucks.renderString(`
    {% set length = images.length if images.length < 13 else 13 %} 
    {% for i in range(0, length) %}
    <img src="/uploads/images/{{images[i].image.filename}}" />
    {% endfor %}`, 
    {images: images} // Imho, assign data to `images`-var is more readable than `index`.
); 
console.log(res);
0
Stephane Rodet On

You can use the loop.index value (documentation) to limit the numbers in a portable way:

{% for images in index %}
  {% if (loop.index <= 5) %}
    <div class="spacer col-md-2 col-sm-6">
    </div>
    <div class="yellp-img col-md-2 col-sm-6">
      <img src="/uploads/images/{{ images.image.filename }}" />
    </div>
  {% endif %}
{% endfor %}