I already do something like this, but as I wrote, this repeats the same <h2> and <a> code in each with clause but with different strings. In this case it might not be a big issue, but there can definitely be scenarios where the common code is much larger, with only some conditional portions that are dependent on parameter values but don’t use the values directly (as in my example). It also doesn’t make to repeat the conditional tests within the common code. This is a basic issue of good modular coding; I’m sure what I want to do is possible, I just need to figure our what’s wrong with my local variable-assignment syntax.
Ok. Here is the syntax without repeating the html elements. It’s a bit of a mouthful but you get the idea. Note the single quotes in the attributes that contain double quotes.
{{ $type := .Get 0 }} <a id='{{ with (eq $type "new") }}new-features{{ end }}{{ with (eq $type "enhancements") }}enhance{{ end }}{{ with (eq $type "fix") }}fixes{{ end }}'</a><h2>{{ with (eq $type "new") }}New Features{{ end }}{{ with (eq $type "enhancements") }}Enhancements{{ end }}{{ with (eq $type "fix") }}Fixes{{ end }}</h2>
Not sure if you can achieve what you want with local variables in Hugo shortcodes. If you manage to get it working feel free to share.
I understand that I can do this, but it does’t really address the basic issue. It’s just another form of repetition but with much less clearer code. Now, consider a large section of code that is common to all shortcode parameter values but has multiple instances within this common code that need different handling based on the same complex conditional logic; it doesn’t make sense to repeat the condition code or the common code multiple times. Every programming language that I ever used ha a way to handle this. But as this digresses from the initial purpose of this forum thread, I’ll try to find the time to investigate this further and if I don’t find a solution I’ll post a new dedicated forum question. Of course, if I find a solution I’ll share as well.
Thank you for taking the time to try and help me with this though :-).
I understand your point 100%.
But the fact is that Golang is very quirky. And its template language not as terse as I would like it to be.
That’s what i’ve learned myself the hard way.
Of course Go has it’s advantages. Meaning Hugo is a single binary, site generation is blazing fast but like everything else in life there are costs involved particularly when it comes to the actual templates. It’s not the most intuitive syntax that I’ve seen.
But anyway I’ve learned to live with it.
Just to make it clear so Go does not get bad reputation:
- There is of course switch in the Go language (aka Golang)
- There is no switch in Go templates, which is the built-in templates in Go
@bep, do you happen to know whether using local variables in Hugo shortcodes, as in my code example, is possible (by design)?
And if not, is it possible in Hugo templates (so I could define a partial template that uses local variables, and call it from a shortcode)?
Very unlikely.
The following is from the Go templates docs at template package - text/template - Go Packages
A variable’s scope extends to the “end” action of the control structure (“if”, “with”, or “range”) in which it is declared, or to the end of the template if there is no such control structure. A template invocation does not inherit variables from the point of its invocation.
For example your $id variable only lives until the next {{ end }}
There is no way around that I’m afraid.
Isn’t the Hugo Scratch construct ([SOLVED] Switch case in templates + using local shortcode variables with Scratch) supposed to bypass this issue? I also saw that the following article demonstrates how to pass variables to a template from a shortcode using Scratch: http://2016.8-p.info/post/06-18-go-html-template/. So far, I hadn’t had time to fully read the Scratch documentation or this article.
I did do a small test using Scratch in my shortcode, but without passing the variables to a template. The test failed but it was written very hastily and it’s quite likely that I got the syntax wrong + maybe it’s only intended for passing variables to templates or other shortcodes?
Yes, Scratch is a workaround. It looks ugly when overused, but it works.
Is Scratch supposed to allow me to use local variables in the shortcode, or only to pass them down to a template?
The “local variable” issue was, in my head when I added Scratch, its primary use case.
Great. So can you maybe give me some tips on how to modify my code to get the local variables to work using Scratch?
You can see the code in this post: [SOLVED] Switch case in templates + using local shortcode variables with Scratch - #8 by sharonl. Thanks.
Of course. You can use Scratch. I forgot all about it. Since I rarely use it. My apologies.
But I would advise you to use Scratch only as a last resort.
For example a while back I modified a code snippet, using Scratch to remove Greek intonation from uppercase letters. It works like a charm but site build time also went noticeably up.
There are plenty of topics about Scratch. Use the forum search and you will find what you need.
So using Scratch can increase my build times, even if it’s just to use two variables?! That might sway me towards keeping the duplication in my code because it’s less important than the build times.
It depends on how many pages you are looping through for these 2 variables.
If your site is small -think <500 pages- then you should be fine.
If your site expands at some point then there will be a cost to pay.
No! Using Scratch to store variables will not have a negative on your build time. Scratch is backed by a Go map, which have a lookup time of 10 nanoseconds; find a dictionary and figure out how small a time unit that is.
The reason I don’t like Scratch is this:
- Proper variable scopes should be built-in (see https://github.com/golang/go/issues/10608)
- It looks kind of out of place.
But it works and will not slow down your site build.
I, for one, would really like to see the Go-templates nested-variables-scoping feature implemented, but I see that https://github.com/golang/go/issues/10608 has been open since Apr 2017 … . I added my vote nonetheless :-). I’ll try to see if I get things working with Scratch. Thank you both, @bep and @alexandros.
OK, so I got it working with Scratch. It was actually very straightforward; it took me 5 minutes to read the doc and implement.
Truth be told, in this specific case the use of the variables don’t save much writing (although my actual shortcode has additional clauses and functionality); but if in the future I want to change the HTML code, for example, I will need to do it only in one place instead of in each with clause.
This is my Scratch variation.
I ultimately decided to use if-else rather than with because as I previously indicated, it will save some unnecessary processing time (because as soon as a match is found, the rest of the conditional clauses won’t be evaluated), and it’s also a bit shorter because it eliminates some with {{ end }} lines.
{{ $type := .Get 0 }}
{{ $.Scratch.Set "id" "" }}
{{ $.Scratch.Set "title" "" }}
{{ if (eq $type "new") }}
{{ $.Scratch.Set "id" "new-features" }}
{{ $.Scratch.Set "title" "New Features" }}
{{ else if (eq $type "enhance") }}
{{ $.Scratch.Set "id" "enhancements" }}
{{ $.Scratch.Set "title" "Enhancements" }}
{{ else if (eq $type "fix") }}
{{ $.Scratch.Set "id" "fixes" }}
{{ $.Scratch.Set "title" "Fixes" }}
{{ end }}
<a id="{{ $.Scratch.Get "id" }}"></a>
<h2>{{ $.Scratch.Get "title" }}</h2>
No need to be harsh.
In my previous reply -not the one you answered to- I shared my experience from the one time I used Scratch.
In my case I used $.Scratch.Set to set the post title as a variable and then replace several characters within it. It did slow down my build time by 20 sec, as I was replacing quite a few characters. (it may not seem like a lot but that site will triple in size within the year).
Anyway I didn’t mean that setting a Scratch variable per se slows down build time. It’s what you do with it that can slow things down, particularly for larger sites.
Not my intention, but saying that “Scratch makes it slow” as a general rule is just not true.