How to access a map value at an index with the index function

I have the following yaml template : consultant.yaml

title: myTitle    
content: myContent  
cards:
  - card:
      title: Title 1 
      args:
        arg1: "blablabla 1"
        arg2: "blablabla 2"
   - card:
      title: Title
      args:
        arg1: "blablabla 3"
        arg2: "blablabla 4"
        arg3: "blablabla 5"

I want to display each arg[x] of my card element using an index and not the key itself. I read about the index function and it seems to be possible.

Hugo doc : 
Soluton 1 : index COLLECTION INDEX
Solution 2 : index COLLECTION KEY

I want to use Solution 1 .

I have the following HTML template : single.html

  {{ range .Site.Data.consultant.consultant.cards }}
  <div class="col-md-4 col-lg-4">
    <div class="">
      <div class="">
        <h3 class=""> {{.title}} </h3>
      </div>

      <p>{{.args}}</p>
      <p>{{ (index .args).arg1}}</p>
      <p>{{ (index .args). 0}}</p>

  </div>
</div>
{{end}}
  • the first p element display a map map[arg1:blablabla 1 arg2:blablabla 2] => OK
  • the second p element display the first value blablabla 1 => OK
  • the third p element display a map map[arg1:blablabla arg2:blablabla 2] => KO.

The third p should display the first element just like the second one and I don’t get why.

Your syntax is wrong.
{{ (index .args "arg1" }}
or
{{ (index .args 0 }}

Hello, Thanks for your answer !

I don’t think the syntax of my second element is wrong because {{ (index .args).arg1}} and {{ index .args "arg1"}} both works.

Nevertheless when I tried the following syntak {{ index .args 0 }}} I have the following error :

…at <index .args 0>: error calling index: value has type int; should be string

It looks like it is just impossible to call the function using anything else than a string to me, I don’t understand…

TL;DR answer:
index COLLECTION INDEX works for arrays
index COLLECTION KEY works for maps


Long answer:

Copying your consultant.yaml:

{{ $test := .Site.Data.consultant }}

$test.cards is an array of maps:

{{ printf "%T" $test.cards }} = []interface {}

so using the syntax index COLLECTION INDEX like the following will work:

1 {{ index $test.cards 0 }}
2 {{ index $test.cards 1 }}
1 map[card:map[title:Title 1 args:map[arg1:blablabla 1 arg2:blablabla 2]]]
2 map[card:map[title:Title args:map[arg1:blablabla 3 arg2:blablabla 4 arg3:blablabla 5]]]

Here, index $test.cards 0 is the equivalent of $test.cards[0]

Let’s assign this to a variable:

{{ $cards0 := (index $test.cards 0) }}

$cards0 is a map:

{{printf "%T" $cards0}} = map[string]interface {}

so using the syntax index COLLECTION KEY the following will work:

3 {{ index $cards0 "card" }}
3 map[title:Title 1 args:map[arg1:blablabla 1 arg2:blablabla 2]]

index $cards0 0 will NOT work because $cards0 is NOT an array, and 0 is not a KEY :

<index $card0 0>: error calling index: value has type int; should be string


Going deeper into $cards0, let's assign this to a variable:
{{ $cards0card := (index $cards0 "card") }}

This is again a map: 
4 {{ printf "%T" $cards0card }}<br>
4 map[string]interface {}

so if we use the syntax index COLLECTION KEY the following will work:

5 {{ index $cards0card "args" }}
5 map[arg1:blablabla 1 arg2:blablabla 2]

and again, index $cards0card 0 will not work.

<index $cards0card 0>: error calling index: value has type int; should be string-->


I suspect possibly that {{ (index .args).arg1}} here doesn’t “work” so much as “fails to fail” (though I am happy to be corrected).

Notice that {{ (.args).arg1 }} returns the same as {{ (index .args).arg1}}. Indeed, {{index .args}} returns the same as {{.args}}.

{{ index .args "arg1"}} works because .args here is a map. The syntax of index COLLECTION INDEX or {{ index .args 0 }} would consequently fail.



So, going back to the goal of

I’m not sure I entirely understand how you wish to accomplish this, but if you just wanted to print them all out you could play around with something like this:

<ul>
{{ range $test.cards }}
  <li>{{.card.title}}
    <ul>
      {{range $key, $value := .card.args}}
      <li>{{$key}}: {{$value}}</li>
      {{end}}
    </ul>
  </li>
{{ end }}
</ul>
  • Title 1
    • arg1: blablabla 1
    • arg2: blablabla 2
  • Title
    • arg1: blablabla 3
    • arg2: blablabla 4
    • arg3: blablabla 5


I hope that all sorta made sense!

3 Likes

Hey pointyfar, Thank you for your help !

With your explanation I was able to do what I wanted.
I was not very clear with the difference between array and map and thanks to you I think I get it better.

Thank you again !