Issue menu/template

Hi, sorry for the unclear title.
You can see down there my menu-hugo.html:

menu.hugo.html

{{ if . }}
{{ template “book-menu-hugo” . }}
{{ end }}

{{ define “book-menu-hugo” }}

{{.params.title}}{{.}}{{end}}
{{ end }}

which doesn’t work. I have this in my config.toml:

[menu]
[[menu.before]]
  name = 'Of Men and Mice'
  url = '/en/troll-en/'
  weight = 3
[[menu.before]]
  name = "Cooking: the Original Sin"
  url = '/en/presentation_instincto_en/'
  weight = 2
[[menu.before]]
  name = 'Power of Love'
  url = '/en/meta_en/'
  weight = 1
[menu.before.params]
  title = 'The Essentials'
  class = 'essentials'

In the wiki there is

[menu]
[[menu.main]]
  name = 'Products'
  pageRef = '/products'
  weight = 10
  [menu.main.params]
    rel = 'external'

The class essentials doesn’t appear in the source code at all.

The code:

<div class=“{{.Params.Class}}”>
<span>{{.Params.Title}}

is causing the errors

/home/drm/WEBSITE/themes/hugo-book/layouts/partials/docs/menu-hugo.html:10:21": execute of template failed: template: partials/docs/menu-hugo.html:10:21: executing “book-menu-hugo” at <.Params.Class>: can’t evaluate field Params in type navigation.Menu
Built in 2366 ms

and

“/home/drm/WEBSITE/themes/hugo-book/layouts/partials/docs/menu-hugo.html:10:15”: execute of template failed: template: partials/docs/menu-hugo.html:10:15: executing “book-menu-hugo” at <.Params.Title>: can’t evaluate field Params in type navigation.Menu
Built in 2331 ms

It blocks on the first of the two lines it encounters.

Thanks for your help

It’s not entirely clear what the issue is. Are you seeing an error message when you try to generate your site? Is the menu not appearing as expected?

1 Like

sorry, I corrected my message.

According to the errors and the code snippet, I think the root cause is that the Children is an array of menu entries, but template book-menu-hugo accepts a menu entry as context, replace it with the following should work.

{{- range .Children }} {{ template "book-menu-hugo" . }} {{- end }}

Not yet.

“/home/drm/WEBSITE/themes/hugo-book/layouts/partials/docs/menu-hugo.html:5:10”: execute of template failed: template: partials/docs/menu-hugo.html:5:10: executing “partials/docs/menu-hugo.html” at <.Children>: can’t evaluate field Children in type navigation.Menu
Built in 2362 ms

Please correct accordingly, because these subtleties are beyond my skills.

{{- range .Children }} {{ template "book-menu-hugo" . }} {{- end }}
{{ define "book-menu-hugo" }}
<div {{with .Params.Class}}class="{{.}}"{{end}}>
{{with .Params.Title}}<span>{{.}}</span>{{end}}
<ul>
  {{ range . }}
  <li>
    <a href="{{ .URL }}" {{ if not .Page }} rel="noopener"{{ end }}>
      {{- .Pre -}}
      {{ with .Page }}
        {{ partial "docs/title" .Page }}
      {{ else }}
        {{ .Name }}
      {{ end }}
      {{- .Post -}}
    </a>
{{- range .Children }} {{ template "book-menu-hugo" . }} {{- end }}
  </li>
  {{ end }}
</ul>
</div>
{{ end }}

Could you please share a public repo for this, I didn’t see how do you invoke this partial.

Ah, no I can’t, it’s complicated.
But here’s how it’s invoked:
In baseof.html:

{{ partial “docs/inject/menu-before” . }}
{{ partial “docs/menu” . }}
{{ partial “docs/inject/menu-after” . }}

menu.html:

{{with .Site.Menus.before}}{{ partial “docs/menu-hugo” . }}{{end}}
{{ partial “docs/menu-filetree” . }}
{{with .Site.Menus.after}}{{ partial “docs/menu-hugo” . }}{{end}}

then menu-hugo.html:

{{ template "book-menu-hugo" . }}

{{ define "book-menu-hugo" }}
	<div {{with .Params.Class}}class="{{.}}"{{end}}>
	{{with .Params.Title}}<span>{{.}}</span>{{end}}
	<ul>
	  {{ range . }}
	  <li>
	    <a href="{{ .URL }}" {{ if not .Page }} rel="noopener"{{ end }}>
	      {{- .Pre -}}
	      {{ with .Page }}
	        {{ partial "docs/title" .Page }}
	      {{ else }}
	        {{ .Name }}
	      {{ end }}
	      {{- .Post -}}
	    </a>
	    {{- with .Children }}
	      {{ template "book-menu-hugo" . }}
	    {{- end }}
	  </li>
	  {{ end }}
	</ul>
	</div>
	  {{ end }}
{{ template "book-menu-hugo" . }}

{{ define "book-menu-hugo" }}
  {{ range . }}
    <div {{ with .Params.Class }}class="{{ . }}"{{ end }}>
      {{ with .Params.Title }}<span>{{ . }}</span>{{ end }}
      <ul>
        <li>
          <a href="{{ .URL }}" {{ if not .Page }}rel="noopener"{{ end }}>
            {{- .Pre -}}
            {{ with .Page }}
              {{ partial "docs/title" .Page }}
            {{ else }}
              {{ .Name }}
            {{ end }}
            {{- .Post -}}
          </a>
          {{- range .Children }}
            <ul>
              {{ template "book-menu-hugo" . }}
            </ul>
          {{- end }}
        </li>
      </ul>
    </div>
  {{ end }}
{{ end }}

It produced a weird code, with one div and ul encircling each menu entry.
This should be correct but gets the same error as before. What the hell is that the context at the beginning of the partial ?

{{ template "book-menu-hugo" . }}
{{ define "book-menu-hugo" }}
<div {{ with .Params.Class }}class="{{ . }}"{{ end }}>
  {{ with .Params.Title }}<span>{{ . }}</span>{{ end }}
  <ul>{{ range . }}<li>
      <a href="{{ .URL }}" {{ if not .Page }}rel="noopener"{{ end }}>
        {{- .Pre -}}
        {{ with .Page }}
          {{ partial "docs/title" .Page }}
        {{ else }}
          {{ .Name }}
        {{ end }}
        {{- .Post -}}
      </a>
      {{- range .Children }}
          {{ template "book-menu-hugo" . }}
      {{- end }}
  </li>{{end}}</ul>
</div>
{{ end }}

I want the following result:

<div class=.Class>
<span>Title</span>
<ul>{{.range entries}}
<li>{{entry}}</li>
...
<li>{{entry}}</li>
</ul></div>

{{ template "book-menu-hugo" . }} passes the Menus (array of MenuEntry) to the book-menu-hugo template. And you’re trying to access the .Params variable of MenuEntry on Menus:

can’t evaluate field Params in type navigation.Menu

Same as Children, it’s belong to MenuEntry:

<.Children>: can’t evaluate field Children in type navigation.Menu

A sample with comments shows how to define a multiple levels menus, and how to read the menu’s params.

[[menu.before]]
name = "A"
identifier = "a"

  [menu.before.params]
  class = "text-success"

[[menu.before]]
name = "A-1"
parent = "a"

[[menu.before]]
name = "A-2"
parent = "a"

[[menu.before]]
name = "B"
identifier = "b"

  [menu.before.params]
  class = "text-danger"

[[menu.before]]
name = "B-1"
parent = "b"

[[menu.before]]
name = "B-2"
parent = "b"

<ul>
  {{ template "book-menu-hugo" . }}
</ul>

{{ define "book-menu-hugo" }}
  {{ range . }}
    <li>
      {{/* Output current menu name. */}}
      <div{{ with .Params.class }} class="{{ . }}"{{ end }}>{{ .Name }}</div>
      <ul style="padding-left: 1rem;">
        {{/* Render children */}}
        {{ with .Children }}
          {{ template "book-menu-hugo" . }}
        {{ end }}
      </ul>
    </li>
  {{ end }}
{{ end }}

Preview:

image

So you mean

[menu.before.params]
class = “text-danger”

is a parameter of

[[menu.before]]
name = “B”
identifier = “b”

and not of the object

[menu.before]

itself ?
If so that element of toml’s syntax is stupidly counterintuitive ! To make sense it should be [[menu.before.class]] instead. “The essentials” is supposed to be not an entry of the menu but the title of it…

Yep. You can convert the TOML to YAML or JSON to have a better view of the structure.

Oh man, I’m done with this, neither yaml’s, toml’s and certainly not Golang’s syntax are remotely as clear and simple as Ada’s. Too bad, I’ll stick with my old, hardcoded solution. Sometimes there’s no point bothering if it only makes the config harder to understand and manipulate.
Still, thanks for the help…

1 Like