Failing to pass partial context when using components

Hi!

Somehow no matter what I do, I’m not able to pass the context when I have my pages built this way:

{{ define "main" }}
{{ range .Params.Components }}

  {{ range $component, $value := . }}

    {{ partial ( printf "components/%s.html" $component ) (dict $component $value ) . }}

  {{ end }}
{{ end }}
{{ end }}

I have a component “article” in “privacy-policy.md”

title: Privacy Policy
components:
    - article:

in the partial I have a {{ .Content }}

but I just won’t show up on the page.

You are calling a partial from within the context of a parameter. Not a typical way to call a partial.

What is the console error?

Also due to the complexity of what it appears that you’re trying to do, please provide a repo with the template structure and sample content.

The full context of the project needs to be seen by people in this forum.

Yes, it’s not typical since I’m playing with the idea of a hugo page builder and building a UI kit with components. There are no console errors…it simple doesn’t call anything because I’m not able to call for data outside of the context of my variable.

Here is our a trimmed down version:

I am not able to call anything outside of the components $value at this point…but would love to be able to call {{ .Content }} and {{ .Site.Params }} as well.

Thanks for the help!

Have a read about the dot: Introduction to Hugo Templating | Hugo

The dot here:

  {{ range $component, $value := . }}

Is the current iteration of

{{ range .Params.Components }}

Nowhere are you passing the actual page context.

Yes exactly and I would love to!

I just don’t know how to call the context from within a component at this point.

The docs page I linked to has an example of how to define a variable independent of the context.

So you would do something like

{{ $page := . }}

{{ range ... }}
  {{ range ... }}
    {{ $partialname := "..." }}
    {{ partial $partialname (dict "pagecontext" $page "foo" "bar")
...

Then in your partial partialname you can access these:

{{ .pagecontext }} -> the page context
{{ .foo }} -> bar

Thank you, you have no idea how much I appreciate that. Im still learning and doing my best to read the docs. In the context of my code, if I were to do something like this, I would be able to call the {{ .Content }} within one of those components?
(this code doesn’t work…I’m still wrapping my head around what you shared.)

    {{ define "main" }}

    {{ $page := . }}

    {{ range .Params.Components }}

      {{ range $component, $value := . }}

        {{ $partialname := "components/%s.html" }}

        {{ partial $partialname (dict "pagecontext" $page "$value")

      {{ end }}
    {{ end }}
    {{ end }}

Before you start testing complicated code, try a simplified version first. This should also help illustrate how the dot changes.

<!-- partials/testpartial.html -->
DOT: {{ . }}
    {{ partial "testpartial" . }}

    {{ range .Params.Components }}
      {{ partial "testpartial" . }}

      {{ range $component, $value := . }}
        {{ partial "testpartial" . }}

Then change the dot that you are passing to the partial into a dict and see how that affects the result.

    {{ $page := . }}
    {{ partial "testpartial" . }}

    {{ range .Params.Components }}
      {{ partial "testpartial" . }}

      {{ range $component, $value := . }}
        {{ partial "testpartial" (dict "X" $page "key" "value") }}

.Content is a page variable. As long as you have access to the Page, you can access its .Content.

Note that dict is made of key-value pairs.

This does not look like pairs.

Have a read about how partials work: Partial templates | Hugo


Thank you @pointyfar at this point I feel like I’m making you waste your time. I’ve been failing to wrap my mind around this for too long already. I really appreciate the help.

{{ $page := . }}

{{ range .Params.Components }}

  {{ partial "testpartial" . }}

  {{ range $component, $value := . }}

    {{ partial "testpartial" (dict "X" $page "$component" "$value") }}

{{ end }}

{{ end }}

This returns:

map[testpartial:map[text:test text]]

map[$component:$value $value:Page(//_index.md)]

What map sequence should I be looking for?

This?

map[testpartial:map:[$components:$value]:Page((/index.md))]

I’ve had some time to have a look at your repo.

In your content/_index.md you have this:


components:
    - article:

This seems incomplete?


If we take your code snippet line by line:

{{ range .Params.Components }}

This will iterate over your components in your frontmatter. components is a list, so each iteration is one list item. In the first iteration the value of the dot inside this range is:

map[article:<nil>]

This dot is now what is being iterated over in the second range. Looking at the first iteration of this range:

{{ range $component, $value := . }}
{{ $component }}: ( {{ $value }} )
{{ end }}

The results are:

article: (  )

Which reflects what is in your frontmatter, i.e., a key named "article" and an empty value.


I don’t entirely understand what you are trying to actually do. Are you trying to pass the value of article? If so, then you need to make sure you actually have a value to pass on.


I am assuming here that you want to be able to call a partial whose name you specify in the frontmatter. In this example, you want the "article" partial. That inner range would then look like this:

{{ range $component, $value := . }}
  {{ $component }}: ( {{ $value }} )
  {{ partial (print "components/" $component) . }}
{{ end }}

Then you need to think about what you want to pass into your partial. Is it only the page context? Do you also want to pass the $value along?

If you only want the page context, then as described a few posts up, you need to “save” the page context into a variable outside of the ranges:

{{ $page := . }}
{{ range .Params.components }}
  {{ range $component, $value := . }}
    {{ $partialname := (print "components/" $component) }}
    {{ partial $partialname . }}
  {{ end }}
{{ end }}

Then from your partial you can call {{ .Content }} as per usual.

If you also want to pass $value along, then you need to pass a dict:

{{ $partialname := (print "components/" $component) }}
{{ $args := dict "page" $page "foo" $value }}
{{ partial $partialname $args }}

Then from your partial, you call the page-related variables slightly differently:

{{ .page.Content }}

and you access your foo :

{{ .foo }} => whatever $value is