Data Template in Shortcode Param

Kia ora,

I am creating a shortcode that aims to render data templates into a more complex HTML layout (homework.html).

What I want to be able to do is to pass a data template file as a parameter to this shortcode, like this:

{{< homework file="$.Site.Data.11sci.as90940.homework" >}}

But I bump into the error:

Error: Error building site: “/Users/finnlesueur/Git/science.lesueur.nz/content/12ess/as91191/homework.md:7:1”: failed to render shortcode “homework”: failed to process shortcode: “/Users/finnlesueur/Git/science.lesueur.nz/themes/hugo-spartan/layouts/shortcodes/homework.html:7:21”: execute of template failed: template: shortcodes/homework.html:7:21: executing “shortcodes/homework.html” at <$homework.topics>: can’t evaluate field topics in type string

This error occurs here:

{{ $homework := .Get "file" }}
<div class="toc">
   <h2>Topics</h2>
   <ol>
   {{ range $homework.topics }}
      <li><a href="#{{ . | urlize }}" title="Jump to {{ . }}">{{ . }}</a></li>
   {{ end }}
   </ol>
</div>

I get that this means it is being evaluated as a string, not as a data template. My question is how do I evaluate it as a data template?

Thanks!

1 Like

That does not work. But you can pass the key to the element you need, e.g:

{{< homework file="11sci.as90940.homework" >}}

And then in your shortcode:

{{ $homework := .Get "file" }}
{{ $data := index site.Data $homework }}

I think the above or a variation of the above should work (untested, just typed it in here)

1 Like

Ah @bep, that does make total sense. I wasn’t aware index could do that.
I do bump into this error, however:

Error: Error building site: “/Users/finnlesueur/Git/science.lesueur.nz/content/11sci/as90940/homework.md:7:1”: failed to render shortcode “homework”: failed to process shortcode: “/Users/finnlesueur/Git/science.lesueur.nz/themes/hugo-spartan/layouts/shortcodes/homework.html:2:16”: execute of template failed: template: shortcodes/homework.html:2:16: executing “shortcodes/homework.html” at <index .Site.Data $key>: error calling index: value is nil; should be of type string

{{ $key := .Get "key" }}
{{ $homework := index .Site.Data $key }}

I have verified that $key is the correct string, and I have verified that .Site.Data returns the proper map, with the proper structure. For some reason that index call is returning nil.

Any thoughts?

It’s easier to help if we can replicate your issue.

Try to add a with or an if block testing for the presence of key before using it in the index statement.

Hm, I think it is an issue with the nested key.

{{< homework file="11sci" >}} gives a map
{{< homework file="11sci.as90940" >}} gives nil
{{< homework file="11sci.as90940.homework" >}} also gives nil

Screen Shot 2020-11-19 at 1.30.34 PM

Ah, I can avoid the nested key by doing this:

{{< homework year="11sci" unit="as90940" >}}
{{ $year := .Get "year" }}
{{ $unit := .Get "unit" }}

{{ $homework := (index (index .Site.Data $year) $unit).homework }}

Seems to work :slight_smile: If there is a solution with nested keys that would be much nicer though!

So you want to split a string at each .? :wink:

{{ $values := split "11sci.as90940.homework" "." }}
{{ range $values }}
{{ . }}
{{ end }}

Sorry - I’m not sure how your answer helps me used a nested key with the index function.

Something like:

{{ $data := site.Data }}
{{ $keys := split (.Get "keys") "." }}

{{ range seq (len $keys) }}
    $data = {{ index $data (index $keys (sub . 1)) }} <br>

    {{ $data = index $data (index $keys (sub . 1)) }}
{{ end }}
<br>
result = {{ $data }}
{{< test keys="one.two.three" >}}
# /data/one/two/three.toml
foo = "bar"

will result in:

$data = map[two:map[three:map[foo:bar]]]
$data = map[three:map[foo:bar]]
$data = map[foo:bar]

result = map[foo:bar]

This thread went long really fast. OK, my memory may be slightly off. Maybe we had plans to add support for “.” keys in index func … @moorereason ?

OK, now I remember. This probably also ties into the “vararg discussion”.