How to pass variable to partial - noob question

Looking into Hugo to develop a static, and with little coding knowledge/expertise. Kinda learning as I go along… I apologize in advance if it is a trivial question or worse namely not knowing at all where it is all about.

I have a index.html, with around 7 html sections. Each section has a title, a description and an image which are defined in the config.toml as so:
[params]

This is Section1

[params.section1]
  enable = true
  title = "Section 1"
  description = "Some text about section 1"
  img = "section1.jpg"

This is Section2

[params.section2]
  enable = true
  title = "Section 2"
  description = "Some text about section 2"
  img = "section2.jpg"

From there the index is calling the sections

{{ if .Site.Params.section1.enable }}
{{ partial “section1.html” .}}
{{ end }}
{{ if .Site.Params.section2.enable }}
{{ partial “section2.html” .}}
{{ end }}

Finally, the partial currently looks like so:

{{ with .Site.Params.section1.title }}{{ . | markdownify }}{{ end }}

I want to clean that up and create a single ‘section.html’ (instead of 7 sections with quasi identical code) using the variables I define in the config.toml. I would prefer to keep the index calling based on the

{{ if .Site.Params.section1.enable }}

So I would like to pass a variable within the index.html to the partial ‘section.html’ so that I can call the variables of the toml from that specific section. In other words:

{{ if .Site.Params.section1.enable }}
       		{{ partial "section.html" .(dict "context" . "section" "Site.Params.section1") }}
{{ end }}

This way, correct me if I’m wrong, I could write in the partial something like

{{ with .context.section.title }}{{ . | markdownify }}{{ end }}
{{ with .context.section.img }}{{ . | markdownify }}{{ end }}

And would only need 1 section to create 7 if enabled in the toml.

Would this make sense, and if so, how would I go about it?

I think I understand your question. I’m assuming here that you want to pass a variable into the shortcode to simplify everything, and not for some other reason. If I’ve got this wrong, please let me know!

First of all, you can create arrays of tables in TOML, and then write something like:

[[params.section]]
  enable = true
  title = "Section 1"
  description = "Some text about section 1"
  img = "section1.jpg"
[[params.section]]
  enable = true
  title = "Section 2"
  description = "Some text about section 2"
  img = "section2.jpg"

Then, you can loop through your params.section tables with something like:

{{ range $.Site.Params.Section }}
  {{ if .enable }}
    {{ partial "section.html" . }}
  {{ end }}
{{ end }}

Note you’ll have to change your shortcode to something like this, because you’re passing the param table in to the shortcode:

    {{ with .title }}{{ . | markdownify }}{{ end }}
    {{ with .img }}{{ . | markdownify }}{{ end }}

If you need both the current context and the $.Site.Params.Section object, your solution is very nearly right! Calling the partial with something like this should work:

{{ partial "section.html" (dict "context" . "section" $.Site.Params.section1 ) }}

(i.e. without the quotes around the object).

1 Like

Thanks for the reply. I should have been more precise, and again might be missing the point. First of all, I’m trying to understand howto, and don’t understand the way variables are passed to the partials. So I tried to keep it simple.

In the index.html I had to change the

{{ partial “section.html” . (dict “context” . “section” $section1) }} into
{{ partial “section.html” (dict “context” . “section” $section1) }}

Then from the partial ‘section.html’ I wrote

{{ with .context.Site.Params.section.description }}{{ . | markdownify }}{{ end }}
Assuming that the variable ‘section’ would be ‘section1’ resulting in the
{{ with .context.Site.Params.section1.description }}{{ . | markdownify }}{{ end }}

Yet I get

undefined variable “$section”

So I assume that something is wrong in the index.html and that the dict is not as it ought to. Would it be a good guess, and a guess it certainly is, that this might have something to do with the variable scoping?

in section.html

{{ with (.context.Param .section).description }}

Ah yep, I typo’d that line! I’ve fixed it now, good catch. :sparkles:

What does $section refer to in your last post? It’s not set anywhere in the snippets that either of us have posted.

[I] don’t understand the way variables are passed to the partials… Would it be a good guess … that this might have something to do with the variable scoping?

Yes! That’s exactly it. Partials are a little confusing in that nothing gets passed to them automatically, and that’s different from the rest of the templating system (where you get access to e.g. page and the $ variables). So everything that is used in a partial needs to be passed into it (when the partial is used / called). The two main patterns for doing this are:

One:

{{ partial "mypartial.html" . }}

That’s what’s referenced in this section of the docs.

Two:

{{ partial "mypartial.html" (dict "something" . "somethingElse" $otherData) }}

This example is more complicated, but basically instead of passing the “.” through, you’re passing in a new dict. This allows you to choose a more complex set of data to pass into the partial. It’s very common to pass in the current context (the “.”) as well as some data from elsewhere in the $.Site. That’s why I was suggesting the names “context” and “section” here:

(dict "context" . "section" $.Site.Params.section1 )

A great way of experimenting with what data is available to partials is to define “mypartial.html” like this:

{{ printf "%#v" . }}
{{ printf "%#v" $ }}

and then call it with different values (Like the dict, the “.”, a string, a number, whatever you like :slight_smile: )

This is a technique referenced in the docs, and it prints the data that’s coming into the partial. The variable scoping section you referenced means that both of these print statements will output the same thing, and that’s all your partial will have access to.

I hope something there makes sense and was helpful to you; it’s hard to explain :sweat_smile:

2 Likes

Thanks for the support! Really appreciated. And I got it to work indeed. Allow me to elaborate a little more to see whether I indeed understand it correctly.

Suppose I write

(dict “context” . “section” $.Site.Params.section1 )

Than the regular “.” is kinda replaced by what you define in the context. For you define a ‘context’ for the “.” and define it with some variable(s). If you would define a variable “section” as above with the value “.Site.Params.section1” you can use the .section.whateverparam in the partial.

If you would write

(dict “context” . “section” .Site.Params.section1 "somethingelse" .Site.Params.Somethingelse)

you could use the .somethingelse to call e.g. “.Site.Params.Somethingelse.whateverparam”. AND call .section.whateverparam.

It took a while before I understood, but where in the docs is the “context” explained. I read here that partials are ‘context-aware’. Is that why I need to use ‘context’ in the dict for the system to know I’m about the provide a context?

Again, I might misunderstand, and have a lot to learn, but it promises to be quite powerful and interesting. Hopefully I can build my skills enough for it to be or become a realistic method of building sites.

Almost!

The “.” in the partial is the same as whatever you pass in as the second argument to partial. So if you write {{ partial "partial.html" 5 }} then the ‘.’ in partial.html would be 5. Similarly, if you pass (dict "cats" 3 "dogs" 4) as the third argument, then from within your partial you can write .cats and get 3, or .dogs and get 4.

There is no magic from labelling part of the dict as “context”: using (dict "context" .) is just a convention so you can still get at the stuff that was in the “.” outside the partial. The “.” is often referred to as the “context”, which is where the name comes from – but it’s just a name :slight_smile:

If you use (dict "context" . [other things]) as your argument to the partial, then in the partial, you can write “.context.[foo]” and that maps to whatever “.[foo]” was when you called the partial. You’re effectively passing the “.” in as part of the argument to the partial.

If you haven’t written .context in your partial, you don’t need to put it in the doc at all.

Cheers, that helped a lot!

1 Like

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.