Range data file but only through selected items

I try to find solution in discourse but nothing found.
I have similar yaml data file like this: products.yaml

- name: product1
  price: 10
- name: product2
  price: 50
- name: product3
  price: 2  
- name: product4
  price: 23
etc.

On every page, I render table with some products (different products and order of products).
How to range only through products I want to use in table ?
Looking for something like this:

{{ range .Site.Data.products  "product7" "product21" "product15" "product3" }}
.. html code for table ..
{{ end }}

Thank you guys

is it possible to use

{{ with (index .Site.Data.products "product7" "product21" "product15" "product3" }}
   ...do some stuff here 
{{ end }}

Not sure but:

{{ range (slice "product7" "product21" "product15" "product3") }}
   {{ with (index Site.Data.products .) }}
       do something here, the dot is your value)
   {{ end }}
{{ end }}

Should work.

In the Front Matter of page:

product: [ "product7", "product21", "product15", "product3" ]

In the template:

{{ range where "Site.Data.products" "intersect" "Params.product" }}
{{ .name }}{{ .price }}
{{ end }}

Not tested.

@Bin951 @regis @Bin951 I have tried to implement all your three suggestions for a few hours but without success.

@Mikhail this is exactly concept what I am looking for. Put name of selected products to Front Matters of .md file and generate a table in the template from them. Unfortunately code is not working for me right now.

But I will take any other solution if it works.
Any advice ? Thanks.

I think @Mikhail suggestion needs one correction. Could you try it with:

{{ range where ".Site.Data.products" "intersect" .Params.product }}

.Params.product instead of "Params.product" and ".Site.Data.products" instead of "Site.Data.products"

But then again, it is untested. We will need a repo of the project for further help. Cheers.

1 Like

Sorry for my previous post, i missed some background.

You’re looking for the name key in your .Site.Data.products so "name" needs to appear before intersect. However, .Site.Data.products should not have quotation marks either, because it’s a variable, like .Params.product.

{{ range where .Site.Data.products "name" "intersect" .Params.product }}

See the where docs :slight_smile:

2 Likes

I’ve got this image of us all perplexly pointing at @Zde’s screen with confusing suggestions :slight_smile: We’re getting there though!

@cmal your wide explanation is perfectly clear and gave me some new pieces to this puzzle. I’ve tested it for a few hours but still no success.

@cmal @regis I create repo for this example project: https://github.com/zdenekpribyla/hugo-range-over-selected-data
There are two spots where I test a range: myPartial and myShortcodes. Default range code is now {{ range .Site.Data.products }} (range through all products…).
Could you guys check the repo? Maybe there is problem with path to .yaml or .Params.
Thanks

Ok I’m sorry I misread your initial post and was under the asumption that “product1” was the key of the whole product, and not just its name. So:

{{ $include := (slice "product1" "product3") }}
{{ range where .Site.Data.products ".name" "in" $include }}
     <li><b>{{ .name }}</b> and price: {{ .price }}</li>
{{ end }}

You could easily retrieve $include from a Front Matter param.

Woops, you’re actually more correct than i was. “intersect” in this case would mean .Site.Data.products items can have many names that can intersect with .Params.product.

However, there’s only one name per product entry, so "in" in more appropriate as you pointed out @regis :

{{ range where .Site.Data.products "name" "in" .Params.product }}

Thank you guys @cmal @regis both solutions works.
I update example project repo

Now there are two issues I fight with.

  1. in output: products are ordered by order in .yaml file. And I need them get in order as they are inserted. For example:
in .md file
---
product: ["product4", "product1", "product3" ]
---

But output is reordered and looks like:

  • product1
  • product2
  • product3
  1. it seems that myShortcode.html (shortcode) does not work with .Params.product
    I mean if I use .Params.product in this part of code:
    {{ range where .Site.Data.products "name" "in" .Params.product }}
    is it hugo feature or bad syntax ?

Thanks again :vulcan_salute:

From whithin your shortcode, you must access the page context using $.Page, so you might try $.Page.Params.product and $.Page.Site.Data.products.

For your yaml ordering, I think its a go map/slice limitation :confused: Not sure what can be done, maybe someone else can find a workaround.

@kaushalmodi usually knows best about such topics :slight_smile:

Hmm, I have never used that before… wouldn’t $.Site.Data.products be the same?

@kaushalmodi usually knows best about such topics

heh, I don’t have a fancy solution for the ordering… I just prefix the items with numbers in a peculiar format (like "01.foo", "02.bar", …) and then just use regex to remove the number prefix ({{ replaceRE $var "^[0-9]+\\." "" }}). I use that trick for ordering menu items without having to save weights in the site config, ordering Data file items, etc.

not sure, maybe.

Summary:

Range over .Site.Data.products (products.yaml) only with products specified in front matter:

---
products: ["product1", "product2"]
---
{{< shortcode >}}

for partial.html

{{ range where .Site.Data.products ".name" "in" .Params.product }}
   .. do some stuff here ..
{{ end }}

for shortcode.html

{{ range where .Site.Data.products ".name" "in" $.Page.Params.product }}
   .. do some stuff here ..
{{ end }}

Entire code on GitHub

Sort is more difficult. I will probably use some kind of other value rating in .yaml and sort like this:
{{ range sort (where .Site.Data.products ".name" "in" $.Page.Params.product) "rating" "desc" }}

Thank you guys for help (and generally your help in Hugo community) :sunglasses:

1 Like

I’m surprised that that worked…

Should it be $.Site. ..?

it works just like: {{ range where .Site.Data.products..

1 Like

Thanks. That’s good to know.

I just stick by the rule of thumb of always using the root context $ within shortcodes.

Hello guys
in my previous issue we found the solution for iteration products name in data file products.yaml where iterated name’s were defined in front matter (see front matter - products):

Page front matter:
---
Title: Table with selected products 
layout: whatever
product: ["product001", "product005", "product011"]
---

Solution:

{{ range where .Site.Data.products ".name" "in" .Params.product }}
   .. do some stuff here ..
{{ end }}

Well, now I am looking for similar syntax but for .Pages.
So every page has .Params pageId and relatedPages in front matter.
And I need iterate over all pageId’s (all pages) which are defined in front matter in relatedPages like this:

---
Title: How to fix a car
pageId: 002
relatedPages: ["001", "003", "007", "012"]
---

I thought I can retrieve the code from previous syntax. Something like this:

{{ range where .Site.Data.Pages ".Params.pageId" "in" .Params.relatedPages }}
   <a href="{{ .URL }}">{{ .Title }}</a><br>
{{ end }}

I have tried lots of syntax combination but it does not work. Also I did not find similar example in discourse. Any advice ?
Thank you.