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.

2 Likes

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.

2 Likes

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
3 Likes

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


1 Like

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

1 Like