Loop through a folder of images and List them in HTML


#1

Sup Hugo Community

Been struggling with this problem for a while. I’m creating a hugo theme for ecommerce websites.
I created the product page. I divided the page in two sections. 1 section for the image carousel of the products and the other section for the product description price and buy button.

My problem arises in the carousel section. I am trying to loop into a folder of images and display them in the carousel. Here’s the code I have so far:

 <div class='carousel-container'>
                    {{ $url := .Title | printf "/products/%s"}}
                    {{ $folder := .Title | printf "/themes/ecom/static/products/%s"}}
                    {{ $files := readDir $folder }}
                    {{ range $files }}
                <div class='carousel-item has-background is-active'>
                  <img class="is-background" src="{{$files}}" alt="" style="width:940px;height:600px;"/>
                </div>
                    {{ end }}
</div>

My goal is to include the image folder for each product in the front matter. And from the single page template, I can just call the image source in the above code and have it display. So far that codes doesn’t show any error but it doesn’t display anything either. Would appreciate any help as I’ve looked everywhere but nobody seems to have this issue.


#2

Hi,

It’s difficult to say what’s going wrong without the full repo, but at least one thing jumps out:

Once you are inside a range the context, or ‘the dot’ changes:

… Inside of an iteration, however, it will have the value of the current item in the loop;


#3

thanks for the reply. I put the whole thing on Github. You can check it out here: https://github.com/LifeOfATitan/ecomTheme


#4

Hi,

If I understood you correctly, you want to have images related to the product show up on each product page. To fix your code snippet without changing anything else, let’s break down your snippet:

  1. Why this does not work:
{{ $url := .Title | printf "/products/%s"}}
{{ $folder := .Title | printf "/themes/ecom/static/products/%s"}}

Taking the pie.md as an example, you do not actually have title defined in the front matter of your individual content files, so {{.Title}} is empty. You seem to have name defined though, so maybe we could use those. We can’t just print out .Name however because it is not in the list of Page Variables available. We need to use it as a Page-level Param {{.Params.name}} instead.

---
name: "Pie"
description: "Good Ass Pie"
price: "$50.29"
size: "Large"
img: "/data/pie/"
---

Pie is capitalised in the front matter, so we also need to pipe it to lower.

{{ $url := .Params.name | lower | printf "/products/%s"}}
{{ $folder := .Params.name | lower | printf "/themes/ecom/static/products/%s"}}

If you try running {{ $files := readDir $folder }} at this point, you will probably get errors complaining about “No such file or directory” because you do not have a similar folder structure in place for the other content files (banana, pineapple, etc). So we check if it exists before trying to readFile by using fileExists:

{{ if fileExists $folder }}
    {{ $files := readDir $folder }}
    {{ range ...
     ...
{{ end }}










  1. Syntax of range: use the ‘dot’ instead of $files inside your range
{{ range $files }}
...
<img class="is-background" src="{{$files}}" ...
...
{{ end }}

Example 1 here shows how to use the range function and the dot. At this point, if you try:

{{ range $files }}
    {{ . }} 
{{ end }}

…the result is probably not what you want.

What actually is in $files? The docs have this to say about readDir :

The readDir function returns an array of os.FileInfo

The example on the same link shows that we can get .Size and .Name. Let’s use .Name:

{{ range $files }}
 <img src="{{.Name}}"  /><br>
{{end}}

… this should result in:

   <img src="pie.jpeg" />
   <img src="pie2.jpeg" />
   <img src="pie3.jpeg" />
   <img src="pie4.jpeg" />





At this point it should be displaying images using the snippet you have.



This is not the best way to do it, however.


  1. It’s generally not a good idea to have content-related files (e.g. product images) inside your theme folder. The idea of creating and using themes is that you can use the same theme in a different site, and a different theme on the same site. It does not make sense to have a pie.jpeg file in your theme static folder if the site is selling cars, for example. Similarly, if you decide to change themes, you will have to keep moving the various images to the new themes.

  2. Consider organising your content into Page Bundles instead of putting your images in static. That would make it easier to manage your Page Resources (i.e. your images).
    There are examples on both those pages as well as on this forum about how to do this.

  3. If you prefer to put your product images under your static folder, do it under the top-level static, not themes/<THEME>/static, for reason #1 above.




One last note: it is generally not a good idea to commit your node_modules folder to git.


#5

Thanks so much for such a detailed explanation of how to do it my way and an explanation of how that way is not efficient at all. Really appreciate your help. It’s making me think in a different manner. Will be organizing my images in each products page bundle.

Also didn’t know about the node_modules. Won’t make that mistake again hehehe.

Thanks again Pointy, you the real MVP