Scratch not resetting?

I may be misunderstanding or missing something with this one, but I have a section template section/project.html that uses {{ .Render “content-list” }} to render each “Page” or project.

Within project/content-list.html I make use of a partial to render an image banner (figure+attribution link etc) as follows:

{{ $.Scratch.Set "bannerparam" "cover-image" }}
{{ partial "img-banner" . }}

Then within the img-banner partial I use

$.Scratch.Get “bannerparam”

to read out the param setting (if set, otherwise it uses “banner” as the param name).

This works fine. However, when it comes to viewing a “single” project which goes via _default/single.html and in turn does {{ .Render “content-full” }} which uses the project/content-full.html to render the individual project, the img-banner partial call within that still sees “bannerparam” as set to whatever it was during the main listing call.

If I load example.com/project/ then the calls to img-banner partial have the bannerparam set as expected. If I directly load example.com/project/specificproject/ then the list template shouldn’t be used and I would expect the scratch variable to not be set, yet it appears to still hold whatever the last scratch setting was.

I have to explicitly set the scratch variable to empty prior to calling the img-banner partial within the single & content-full templates.

Is that expected behaviour? If so, is there any way to set a scratch var that only applies as hugo goes deeper down the stack and does not bubble up beyond the page that sets it?

Scratch has the scope of the “.” (i.e. the Page) you call it with. That is the whole point of Scratch. So, if you see the same value, you use the same “.”.

I know that was poorly explained, but I don’t know how to make it simpler.

And a general remark: Instead of writing a whole novel that I really don’t have time to read and understand, it is easier if you can point to a file on a project on GitHub which shows the problem you’re having.

@bep: I can’t link to it as it’s not an open site atm with no source available publicly. That’s why I tried to be a little more detailed in describing how it’s setup to avoid been asked for more detail.

How you describe scratch is inline with what I was expecting, but what I’m seeing in this case is

list page -> set scratch “hello”, call partial, partial sees scratch var "hello"
single page -> no setting scratc, call partial, partial sees scratch var containing “hello” still.

I didn’t expect the list or single to end up sharing the same scope.

FWIW: in _default/single.html if I display the scratch value via {{ $.Scratch.Get “bannerparam”}} when nothing has set the var other than in the section/project.html page, the scratch var has a value that matches the one the section/project.html page set.

Those two pages are in different scopes aren’t the?

Yes, they are.

But when you on a list page range over a list of pages, you have to think careful about the “.”, it gets esp. potentially confusing when you pass the “.” into partials you reuse from different places (header.html etc.). So, when you think you got a “single page”, you may as well really have a “list page”.

The “$.” way of accessing the outermost context can help a little, but you still have to think.

I am fairly confident that Hugo does the right thing here. If you still think it is an issue here, it would be good if you create a small test site that identifies the problem.

With that said, your solution looks hacky. If you need to send multiple parameters into the partial, have a look at the dict template func.

@bep: despite reading through the docs several times I couldn’t see a way to pass anything into a partial other than via scratch, must have glossed over dict multiple times. That’s a much better solution thanks.

Yes, it is not clear how to pass variables to partial. What if you want to pass a variable with dict, but also want to pass current context “.” as in simple partial call?

The following example does not work:

{{ partial "menuitems" (dict "name" "Tom") . }}

I’ve not tried any of this yet, but I think you can just pass “current” . (that’s a period as in the current context not a full stop) then in the partial you can use current as you would normally use “.”

e.g

{{ partial “menuitems” (dict “current” . “name” “Tom”) }}

That seems to be what the docs suggest anyway for the “current” and “important” example.

2 Likes

Now I understand - thanks. I have tried to assign the dot to the “current” variable, but till now I didn’t realize that I should also refactor my partials.