Skip to content
Advertisement

Nodejs/Express/JSON/Handlebars loop through array not working with multiple values

I am having problems understanding how to loop through an object in Handlebars and possibly passing information from one place to another.

Below is a sample json file which I need to read from. In this example, it’s just a bunch of image file names that I want to pull in.

This json file is called “testdata.json” and it has:

{
  "artists": 
  [
    {
        "name": "person 1",
        "artwork": ["pic1.jpg", "pic2.jpg", "pic3.jpg", "pic4.jpg"]
    },
    {
        "name": "person 2",
        "artwork": ["pic1.jpg", "pic2.jpg", "pic3.jpg", "pic4.jpg"]
    },
    {
        "name": "person 3",
        "artwork": ["pic1.jpg", "pic2.jpg", "pic3.jpg", "pic4.jpg"]
    },
    {
        "name": "person 4",
        "artwork": ["pic1.jpg", "pic2.jpg", "pic3.jpg", "pic4.jpg"]
    }
  ]
}

And in app.js, I require it to a variable by the same name testdata.

const testdata = require('./data/testdata.json');

Then I pass it in alongside “app” to my homepage route file via

homepageRoute(app, testdata);

I want to get the array with image filenames from testdata, pass it in to the homepage (index.hbs) via a route, and then let handlebars iterate over the array to form a mini image gallery.

Here is what my sample routes file for the homepage looks like:

 module.exports = function homepageRoute(app, testdata){
   
        app.get('/', function(request, response){
    
            var TestWholeArray = testdata.artists[0].artwork;    
    
            response.render('index', {
                pageTitle : "Home Page",
                pageId : "home",
                artistArtwork : TestWholeArray 
            });
        });
    }

When I do:

Handlebars in index:

{{#each artistArtwork}}
   <div class="PICSHERE">
      <img src="images/artwork/{{artistArtwork}}" alt="">
   </div>
{{/each}}

The images don’t appear, and when I look at the back end code via the console, I see this come out:

<div class="PICSHERE"><img src="images/artwork/"" alt=""></div>
<div class="PICSHERE"><img src="images/artwork/"" alt=""></div>
<div class="PICSHERE"><img src="images/artwork/"" alt=""></div>
<div class="PICSHERE"><img src="images/artwork/"" alt=""></div>

The filename never comes out. When testing and trying to console.log(TestWholeArray ); in terminal, I do see and get this:

[ 'pic1.jpg',
  'pic2.jpg',
  'pic3.jpg',
  'pic4.jpg' ] 

To minimize the test even further, when I take the same test above, but instead of using this:

var TestWholeArray = testdata.artists[0].artwork;

I dig a little deeper into the array to pull in just one image as oppose to all of them via:

var TestWholeArray = testdata.artists[0].artwork[0];

Then it does work and the image does appear. It’s when I try to pass in more than one that it goes bonkers.

What am I doing wrong or what am I missing?

Advertisement

Answer

When looping an array, use {{this}} to access the current value.

{{#each artistArtwork}}
   <div class="PICSHERE">
      <img src="images/artwork/{{this}}" alt="">
   </div>
{{/each}}

What you were trying to do, is to access the property artistArtwork from the array artistArtwork which of course, doesn’t exist.


Working demo:

let data = {
  "artists": 
  [
    {
        "name": "person 1",
        "artwork": ["pic1.jpg", "pic2.jpg", "pic3.jpg", "pic4.jpg"]
    },
    {
        "name": "person 2",
        "artwork": ["pic1.jpg", "pic2.jpg", "pic3.jpg", "pic4.jpg"]
    },
    {
        "name": "person 3",
        "artwork": ["pic1.jpg", "pic2.jpg", "pic3.jpg", "pic4.jpg"]
    },
    {
        "name": "person 4",
        "artwork": ["pic1.jpg", "pic2.jpg", "pic3.jpg", "pic4.jpg"]
    }
  ]
};

let artistTemplate = `{{#each artistArtwork}}
   <div class="PICSHERE">
      <img src="images/artwork/{{this}}" alt="">
   </div>
{{/each}}`;

let template = Handlebars.compile(artistTemplate);
console.log(template({ artistArtwork: data.artists[0].artwork }));
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.8/handlebars.js"></script>
Advertisement