if statments in golang hugo - if-statement

I'm trying to create HTML layout partial to add different html elements using the front matter as a data source and hugo templating for the rendering.
For example the front matter has this property
---
animal:
type:"bear"
---
now the partial looks like this:
{{ if eq .Params "animal.type" "dog" | or eq .Params "animal.type" "bear" | or eq .Params "animal.type" "fox" | or eq .Params "animal.type" "wolf" }}
<p> Belongs to the Canine family, they have distinctive fangs. <p>
{{ end }}
throws the following error when i run hugo server:
executing "partials/canine.html" at : wrong number of args for eq: want at least 1 got 0
Am i doing the piping of the or operators wrong ? Or what is the issue ?
the folder structure looks like this: the single.html is calling the animalsDetails.html this one is calling canine.html I don't think the it is the problem, but just in case.
|layouts
|_defaults
single.html
|partials
animalDetails.html
canine.html

You probably need to use .Params properly and ensure use of round braces.
Try this (not tested):
{{ if eq .Params.animal.type "dog" | or (eq .Params.animal.type "bear") | or (eq .Params.animal.type "fox") | or (eq .Params.animal.type "wolf") }}
<p> Belongs to the Canine family, they have distinctive fangs. <p>
{{ end }}
I would suggest against using bars in Hugo expressions, I have ran into problems with them (though that was a case of replaceRE).
Here's the solution w/o use of bars:
{{ if or (eq .Params.animal.type "dog") (eq .Params.animal.type "bear") (eq .Params.animal.type "fox") (eq .Params.animal.type "wolf") }}
<p> Belongs to the Canine family, they have distinctive fangs. <p>
{{ end }}
Feel absolutely free to comment if you need more help! 🙃
Edit 1: Fixed a typo and added alternative recommended solution.

{{ if or (eq .Params.animal.type "dog") (eq .Params.animal.type "bear") (eq .Params.animal.type "fox") (eq .Params.animal.type "wolf") }}
<p> Belongs to the Canine family, they have distinctive fangs. <p>
{{ end }}
that did it

Related

Django include template as variable to use in default

I'd like to include a default template as a variable to pass it into a default case, like below:
<div class="row max-h-200 overflow-hidden">
{% include 'blog/userprofile_deleted.html' as deleted_profile %}
{{ user.profile.bio | safe | default:deleted_profile }}
</div>
Is this possible in django 3.2.9 ?
Currently I have to write out the default text as html in a single line:
<div class="row max-h-200 overflow-hidden">
{{ user.profile.bio | safe | default:'<h4> Very long html string! </h4> <span>Comment as <b>you</b> with your own profile!</span><span>Create your Account at the bottom of the page,or by visiting <code>/register</code> !</span>' }}
</div>

Check if the current path in gohugo matches a pattern with regex

I'm trying to check if the current url is of the format : http://localhost:1313/categories/.../ so matching routes under categories route, using regular expression.
I tried this:
{{if (eq .Permalink (`categories/*/` | absURL))}}
<h4 class="mb-3 text-dark font-weight-bold">
Showing posts with <mark>{{.Title}}</mark> category
</h4>
{{else}} # means :{{if (eq .Permalink (`tags/*/` | absURL))}}
<h4 class="mb-3 text-dark font-weight-bold">
Showing posts with <mark>{{.Title}}</mark> tag
</h4>
{{end}}
Any help or advice will be appreciated, thank you.

Golang template and testing for Valid fields

In Go's database/sql package, there are a bunch of Null[Type] structs that help map database values (and their possible nulls) into code. I'm trying to figure out how to test whether a struct field is null, or in other words, when its Valid property is false.
The recommended way to print a SQL field is to use the .Value property, like this:
<div>{{ .MyStruct.MyField.Value }}</div>
This works great.
But suppose I have something slightly more complicated, where I need to test the value against something else, for example:
<select name="y">
{{ range .SomeSlice }}
<option value="{{ . }}" {{ if eq $.MyStruct.MyField.Value .}}selected="selected"{{ end }}>{{ . }}</option>
{{ end }}
</select>
As it happens, this works great, too, unless .MyField is not Valid, in which case I get the error, "error calling eq: invalid type for comparison". The error makes sense, because Go can't compare a nil Field against another value (or something like that).
I would have thought the 'easy' solution would be to test first whether the Value is nil, and then compare it against what I need, like this:
<select name="y">
{{ range .SomeSlice }}
<option value="{{ . }}" {{ if and ($.MyStruct.MyField) (eq $.MyStruct.MyField.Value .)}}selected="selected"{{ end }}>{{ . }}</option>
{{ end }}
</select>
In this case, I get the same "error calling eq: invalid type for comparison". I guess that means .MyField "exists" even though the value of .MyField is not Valid. So, then I tried a half dozen other versions, mostly with the same error, for example:
<select name="y">
{{ range .SomeSlice }}
<option value="{{ . }}" {{ if and ($.MyStruct.MyField.Valid) (eq $.MyStruct.MyField.Value .)}}selected="selected"{{ end }}>{{ . }}</option>
{{ end }}
</select>
At this point, I'm realizing I really don't understand how to test for the existence of a valid field at all. I'd appreciate any help you might have.
Thanks.
The and function in Go templates is not short-circuit evaluated (unlike the && operator in Go), all its arguments are evaluated always. Quoting from text/template package doc:
and
Returns the boolean AND of its arguments by returning the
first empty argument or the last argument, that is,
"and x y" behaves as "if x then y else x". All the
arguments are evaluated.
This means that the {{if}} action of yours:
{{ if and ($.MyStruct.MyField) (eq $.MyStruct.MyField.Value .)}}
Even though the condition would be evaluated to false if $.MyStruct.MyField is nil, but eq $.MyStruct.MyField.Value . will also be evaluated and result in the error you get.
Instead you may embed multiple {{if}} actions, like this:
{{if $.MyStruct.MyField}}
{{if eq $.MyStruct.MyField.Value .}}selected="selected"{{end}}
{{end}}
You may also use the {{with}} action, but that also sets the dot, so you have to be careful:
<select name="y">
{{range $idx, $e := .SomeSlice}}
<option value="{{.}}" {{with $.MyStruct.MyField}}
{{if eq .Value $e}}selected="selected"{{end}}
{{end}}>{{.}}</option>
{{end}}
</select>
Note:
You were talking about nil values in your question, but the sql.NullXX types are structs which cannot be nil. In which case you have to check its Valid field to tell if its Value() method will return you a non-nil value when called. It could look like this:
{{if $.MyStruct.MyField.Valid}}
{{if eq $.MyStruct.MyField.Value .}}selected="selected"{{end}}
{{end}}

Display part of the content data

I have the following template code:
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">{{ article.title }}</h3>
</div>
<div class="panel-body">
{{ article.content }} <!--will display the full text-->
</div>
I intend to show the first 200 characters of the content, like:
{{ article.content|length=200 }}
How to achieve such a constrain on the text.
There are two template filters here that are useful: slice and truncatechars.
slice limits an iterable (here a string) to a given number, for example:
{{ variable | slice:":200" }}
whereas truncatechars does approximately the same, except that in case the string is longer than the upper bound (here 200), it will slice to the upperbound minus three, and add an ellise:
{{ variable | truncatechars:"200" }}
For a smaller upperbound, to demonstrate the difference, for a string variable = "foobarqux" we would get:
{{ variable | slice:":6" }} # foobar
{{ variable | truncatechars:"6" }} # foo...
The two thus differ: the latter gives a textual hint that there is actually more content. Of course it depends on the specific situation which filter suits your needs.
A nice thing is that you can emulate truncatechars in terms of slice:
{{ variable | truncatechars:":6" }}
is equivalent to:
{% if variable|length > 6 %}{{ variable|slice:":3" }}...{% else %}{{ variable }}{% endif %}
But it is of course not the most elegant solution: in case you want truncatechars behavior, it is better to use the specific filter.
You can use truncatechars filter:
{{ article.content|truncatechars:200 }}

Golang pagination

I need to implement pagination. Actually I have pages array, page param and per_page variable.
In my code:
pages_count := math.Floor(float64(len(pages)) / float64(per_page))
then in template I need something like (pseudocode):
{{ if .page - 2 > 0 }}
{{ $start_page := .page - 2 }}
{{ else }}
{{ $start_page := 1 }}
{{ end }}
{{ if .page + 2 >= .pages_count }}
{{ $finish_page := .page + 2 }}
{{ else }}
{{ $finish_page := .pages_count }}
{{ end }}
<ul>
{{ for $i := $start_page; $i <= $finish_page; ++$i }}
<li {{ if $i == .page }} class="current_page" {{ end }}>
$i
</li>
{{ end }}
</ul>
How to implement this correctly?
Thx
When I work with Java templates (e.g. Velocity), I find that the kinds of template logic you are asking about lead to over-complex templates. The same applied in Go.
My solution is to move logic into the view-model layer and keep the templates rather dumb. This means that the controller and view model have to do a bit more work precomputing the kinds of values that your template shows. The view model is consequently larger - but it's just simple data and is easy to unit-test.
In your specific example, you would keep the for-loop that builds up the <li> list. Everything above the <ul> open tag can be handled in the view model. So the template would just work with some precomputed data.