HUGO

The advanced table, using Go and YAML, does not generate the part "tbody"

Hello

I am building an advanced table based on a table of icons by colours from Available colours in Suru++ 25 that I built in pure HTML.

But only the tbody part is missed. I spent 5 hours, trying to find several alternatives solutions, but no luck.

First, look at a file data/themes.yaml:

icons:
  - name: adwaita-plus
    title: Adwaita++
    table:
      thead:
        - tr:
          - th: Name
          - th: Preview
      tbody:
        - tr:
          - th: "90ssummer"
            td:
              - apps
              - documents
              - downloads
        - tr:
          - th: aubergine
            td:
              - apps
              - documents
              - downloads
        - tr:
          - th: aurora
            td:
              - apps
              - documents
              - downloads

  - name: suru-plus
    title: Suru++
    table:
      thead:
        - tr:
          - th: Name
          - th: Preview
      tbody:
        - tr:
          - th: "90ssummer"
            td:
              - apps
              - documents
              - downloads
        - tr:
          - th: aubergine
            td:
              - apps
              - documents
              - downloads
        - tr:
          - th: aurora
            td:
              - apps
              - documents
              - downloads

I created a shortcode on the folder layouts/shortcodes/themes.html, it looks like:

{{ range .Site.Data.themes.icons }}
<h2>{{ .title }}</h2>

  {{ range .table.thead }}
  <table>

    <thead>
      <tr>
        {{ range .tr }}
        <th>{{ .th }}</th>
        {{ end }}
      </tr>
    </thead>

    {{ range .table.tbody }}
    <tbody>
      {{ range .tr }}
          {{ range .th }}
            <tr>
              <th>{{ . }}</th>
              <td>
                {{ range .td }}
                  <img alt="folder-{{ .th }}-{{ . }}" src="folder-{{ .th }}-{{ . }}.svg">
                {{ end }}
              </td>
            </tr>
          {{ end }}
      {{ end }}
    </tbody>
    {{ end }}

  </table>
  {{ end }}
  
{{ end }}

Expected result:

<h2>Adwaita&#43;&#43;</h2>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Preview</th>
    </tr>
  </thead>
</table>

<h2>Suru&#43;&#43;</h2>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Preview</th>
    </tr>
  </thead>
</table>

But in this code, the part tbody went missed.

The output should be like:

<h2>Adwaita&#43;&#43;</h2>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Preview</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>90ssummer</th>
      <td>
        <img alt="folder-90ssummer-apps" src="folder-90ssummer-apps.svg">
        <img alt="folder-90ssummer-documents" src="folder-90ssummer-documents.svg">
        <img alt="folder-90ssummer-downloads" src="folder-90ssummer-downloads.svg">
      </td>
    </tr>
    <tr>
      <th>aubergine</th>
      <td>
        <img alt="folder-aubergine-apps" src="folder-aubergine-apps.svg">
        <img alt="folder-aubergine-documents" src="folder-aubergine-documents.svg">
        <img alt="folder-aubergine-downloads" src="folder-aubergine-downloads.svg">
      </td>
    </tr>
    <tr>
      <th>aurora</th>
      <td>
        <img alt="folder-aurora-apps" src="folder-aurora-apps.svg">
        <img alt="folder-aurora-documents" src="folder-aurora-documents.svg">
        <img alt="folder-aurora-downloads" src="folder-aurora-downloads.svg">
      </td>
    </tr>
  </tbody>
</table>

<h2>Suru&#43;&#43;</h2>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Preview</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th>90ssummer</th>
      <td>
        <img alt="folder-90ssummer-apps" src="folder-90ssummer-apps.svg">
        <img alt="folder-90ssummer-documents" src="folder-90ssummer-documents.svg">
        <img alt="folder-90ssummer-downloads" src="folder-90ssummer-downloads.svg">
      </td>
    </tr>
    <tr>
      <th>aubergine</th>
      <td>
        <img alt="folder-aubergine-apps" src="folder-aubergine-apps.svg">
        <img alt="folder-aubergine-documents" src="folder-aubergine-documents.svg">
        <img alt="folder-aubergine-downloads" src="folder-aubergine-downloads.svg">
      </td>
    </tr>
    <tr>
      <th>aurora</th>
      <td>
        <img alt="folder-aurora-apps" src="folder-aurora-apps.svg">
        <img alt="folder-aurora-documents" src="folder-aurora-documents.svg">
        <img alt="folder-aurora-downloads" src="folder-aurora-downloads.svg">
      </td>
    </tr>
  </tbody>
</table>

You can check my original Markdowm code in pure HTML whose link I gave above.

Important

Not all themes have the available colours (for example, 90ssummer, aubergine and aurora are colours). And not all available colour folders have available categories (for example, apps, documents and downloads are categories). Or at the JavaScript file, you can check getColorsBasedOnTheStyle and getCategoriesBasedOnTheStyle containing indexOf and slice, what means some inexistent categories and icons are excluded from each theme.

Thank you a lot for your attention, help, patience and understanding!

You have a context problem. Due to nested range statements, you are trying to range through .table.thead.table.tbody.

In a HTML or YAML file?

I also have already moved the contexts and statements in the YAML, but no luck. I also tried with just .tbody instead of .table.tbody.

Maybe because of .table.

First, read this:
https://regisphilibert.com/blog/2018/02/hugo-the-scope-the-context-and-the-dot/

Second, this is your template code (the stuff in the HTML file):

{{ range .Site.Data.themes.icons }}
  {{ range .table.thead }}
    {{ range .tr }}
      ...
    {{ end }}
    {{ range .table.tbody }} {{/* context is .table.thead */}}
      {{ range .tr }}
        {{ range .th }}
        {{ range .td }}
          ...
        {{ end }}
      {{ end }}
    {{ end }}
  {{ end }}
{{ end }}

While ranging through .table.thead you attempt to range through .table.body, which means you’re trying to access .table.thead.table.body which doesn’t exist in your data structure.

Following the logic of the article, using the context, I tried three solutions, and the tbody with tr appeared, but without the variable tbody, I was unable to extract tbody.tr and tbody.tr.th from the YAML data.

Solution 1:

{{ range .Site.Data.themes.icons }}
<h2>{{ .title }}</h2>

  {{ with .table.thead }}
  <table>
    {{ range . }}
    <thead>
      <tr>
        {{ range .tr }}
            <th>{{ .th }}</th>
        {{ end }}        
      </tr>
    </thead>
    {{ end }}

    {{ range . }}
    <tbody>
          {{ range .tr }}
            <tr>
              <th>{{ .th }}</th>
            </tr>
          {{ end }}        
    </tbody>
    {{ end }}

  </table>
  {{ end }}  {{/* .table.thead */}}
{{ end }} {{/* .Site.Data.themes.icons */}}

Solution 2:

{{ range .Site.Data.themes.icons }}
<h2>{{ .title }}</h2>

  {{ with .table.thead }}
  <table>
    {{ range . }}
    <thead>
      <tr>
        {{ range .tr }}
            <th>{{ .th }}</th>
        {{ end }}        
      </tr>
    </thead>
    {{ end }}

    {{ range . }}
    <tbody>
      {{ range .tr }}
      <tr>
            <th>{{ .th }}</th>
      </tr>     
      {{ end }}        
    </tbody>
    {{ end }}

  </table>
  {{ end }}  {{/* .table.thead */}}
{{ end }} {{/* .Site.Data.themes.icons */}}

Solution 3:

{{ range .Site.Data.themes.icons }}
<h2>{{ .title }}</h2>

  {{ with .table.thead }}
  <table>
    {{ range . }}
    <thead>
      <tr>
        {{ range .tr }}
            <th>{{ .th }}</th>
        {{ end }}        
      </tr>
    </thead>
    {{ end }}

    {{ range . }}
    <tbody>
      {{ with .tr }}
        {{ range . }}
        <tr>
            <th>{{ .th }}</th>
        </tr>     
        {{ end }}
      {{ end }}        
    </tbody>
    {{ end }}

  </table>
  {{ end }}  {{/* .table.thead */}}
{{ end }} {{/* .Site.Data.themes.icons */}}

It will probably help you to name the dots, so you don’t lose track of what they are at any level:

Below, anything ending in an i is a list item; i.e. $listi = $list[i]

{{ $data := .Site.Data.... }}

{{ range $data.icons }}
  {{ $iconi := . }} <!-- $iconi = $data[icons][i] -->

  <h2>$iconi.name:</h2>
  {{ $iconi.name }}

  <h2>$iconi.title:</h2>
  {{ $iconi.title }}

  <h2>$iconi.table:</h2>
 
  {{ $table := $iconi.table }}

  {{ $thead := $table.thead }}
  {{ $tbody := $table.tbody }}
  
  begin range $thead <br>
  {{ range $thead }}
    {{ $theadi := . }}
  --begin range $theadi <br>
    {{ range $theadi }}
    {{ $tr := . }}
    <br>
  ----begin range $tr <br>
      {{ range $tr }}
        {{ $tri := . }}
        {{ $th := $tri.th }}
        <strong>$th:</strong>{{ $th }}<br>
      {{ end }}
  ----end range $tr <br>
      <br>
    {{ end }}
  --end range $theadi <br>
  {{ end }}
  end range $thead <br>

  <hr>

  begin range $tbody <br>
  <br>
  {{ range $tbody }}
    {{ $tbodyi := . }}
  --begin range $tbodyi <br>
    {{ range $tbodyi }}
      {{ $tr := . }}
  ----begin range $tr <br>
      {{ range $tr }}
        {{ $tri := . }}

        {{ $td := $tri.td }}
        {{ $th := $tri.th }}
        
        <strong>$td:</strong>{{ $td }}<br>
        <strong>$th:</strong>{{ $th }}<br>

      {{ end }}
  ----end range $tr <br>
    {{ end }}
  ----end range $tbodyi <br>
  <br>
    {{ end }}
    end range $tbody <br>
    <hr>
    <hr>

{{ end }}

I analysed and tested your code, but the log informed parse failed: template: shortcodes/themes.html:1: unexpected <.> in operand because of .Site.Data..... I corrected it, the table did not appear. I also have tested with $iconi = $data[icons][i] uncommented, but it gave an error unexpected bad character U+005B '[' in command.

Based on the answer to the question “How do I create a table for haml using loop directly in ruby file?”, I think I’ll use HAML to convert to YAML and readpt the YAML and the Hugo HTML files.

Update

No need to answer. I have corrected your code .Site.Data... to .Site.Data.themes. I also corrected

{{ $td }}
{{ $th }}

to

<th>
  {{ $th }}
</th>
<td>
  {{ range $td }}
    <img alt="folder-{{ $th }}-{{ . }}" src="folder-{{ $th }}-{{ . }}.png">
  {{ end }}
</td>

It worked like:

What If I will simplify condensedly from:

tbody:
  - tr:
    - th: "90ssummer"
      td:
        - apps
        - documents
        - downloads
  - tr:
    - th: aubergine
      td:
        - apps
        - documents
        - downloads
  - tr:
    - th: aurora
      td:
        - apps
        - documents
        - downloads

to

tbody:
  - tr:
    - th: 
        - "90ssummer"
        - aubergine
        - aurora
      td:
        - apps
        - documents
        - downloads

or

tbody:
  - tr:
    - th: "90ssummer"
    - th: aubergine
    - th: aurora
      td:
        - apps
        - documents
        - downloads

?

Regardless of what form your data looks like, you will need to understand how the dot context works so you can adapt your code accordingly. Do it one range at a time, print out the dot, rename the dot to something that makes more sense, then move on from there.

My example code was just that, an example, for how you might go about assigning the context to a variable with a more descriptive name.

I was trying to translate the data files, but it gave no effect. I learned from @bep’s tips from Can data files be translated?.

  • shortcodes/themes.yaml:
{{ $data := (index .Site.Data.themes .Site.Language.Lang) }}
{{ range $data.icons }}
  {{ $iconi := . }}
   <!-- ...  -->
      <tr>
        {{ range $tr }}
          {{ $tri := . }}
          {{ $th := $tri.th }}
          <th class="c">
            {{ i18n $th }}
          </th>
        {{ end }}
      </tr>
   <!-- ...  -->
{{ end }}

Tree:

data
├── themes
│   ├── en
│   │   └── themes.yaml
│   └── fr
│       └── themes.yaml
└── themes.yaml
  • data/themes/en/themes.yaml:
icons:
  - name: adwaita-plus
    title: Adwaita++
    table:
      thead:
        - tr:
          - th: Name
          - th: Preview
  • data/themes/fr/themes.yaml:
icons:
  - name: adwaita-plus
    title: Adwaita++
    table:
      thead:
        - tr:
          - th: Nom
          - th: Aperçu

Update

Sorry, @inwardmovement’s answer worked:

{{ $data := (index .Site.Data.themes .Site.Language.Lang) }}

{{ range $data.themes.icons }}
      <tr>
        {{ range $tr }}
          {{ $tri := . }}
          {{ $th := $tri.th }}
          <th class="c">
            {{ $th }}
          </th>
        {{ end }}
      </tr>
{{ end }}