I've got this template that parses multiple items of a slice onto the page. It does that really well.
However, I now want to use the very same template to parse a single value of the slice, based on the range index. The slice is used in multiple files so I can't just .Execute it like Slice[1:2]
{{ $bpi := .Index}}
{{ range $i, $elmt := .Slice }}
{{ if $bpi.Equals $i }}
<div>{{ .SliceContent }}</div>
{{ end }}
{{ end }}
From what I've read is that the template isn't ment for computation, but if you've got a range index and if-statements in the html/template package it seems to me that I must be doing something wrong. I can write a FuncMap ofcourse, no problemo. But it doesn't seem right to me given these facts.
I am using something like this to conditionally include a default image or the first from a supplied slice of pictures. So I think this will provide you with the basis to do what you want. I check the slice has values, pulling the Nth item using the {{index .Slice n}} syntax as follows:
{{ $idx := 2}}
{{if .Pictures}}
<img src="{{if .Pictures}}{{index .Pictures $idx}}{{end}}" alt="supplied first picture">
{{else}}
<img src="http://fpoimg.com/200x200?text=Placeholder(FPOimg.com)" alt="default picture">
{{end}}
Therefore you can do the following:
{{ $bpi := .Index}}
{{ if .Slice }}
{{ index .Slice $bpi }}
{{ end }}
Related
I’m working with this tutorial which has the following lines:
{% set user_link %}
<span class="user_popup">
<a href="{{ url_for('main.user', username=post.author.username) }}">
{{ post.author.username }}
</a>
</span>
{% endset %}
{{ _('%(username)s said %(when)s',
username=user_link, when=moment(post.timestamp).fromNow()) }}
It looks this was specifically because he uses Babel translate, which he talks about on his blog.
My question is, how can I make this work when I strip all the Babel code out, because I don’t need any translation, specifically the bit after end set.
This is the sort of thing I tried but could never get the replacement correct:
{{username, username=user_link }} said {{when,when=moment(post.timestamp).fromNow())}}
{{ user_link }} said {{ moment(post.timestamp).fromNow() }}
The arguments after the string define the replacement map for the different keywords, so:
%(username)s will be replaced by user_link, because username=user_link
$(when)s will be replaced by moment(post.timestamp).fromNow(), because when=moment(post.timestamp).fromNow()
The s ending the $(placeholder)s is there to indicate that the placeholder should be considered as a string.
So I just noticed that when I try to access something from .Site itself inside a range block it returns as null/blank.
Here's an example:
<div class="row weekday">
{{ .Site.Data.company.social_media.whatsapp }}
{{ range $entry := sort .Site.Data.events "order" "asc" }}
<div class="col-sm-6 col-md-4 col-lg-4">
{{ .Site.Data.company.social_media.whatsapp }}
{{ partial "events_detail.html" (dict "entry" $entry) }}
</div>
{{ end }}
</div>
The first .Site.Data.company.social_media.whatsapp (before the range) renders a phone number.
The second .Site.Data.company.social_media.whatsapp (after the range) do not renders anything.
This same behavior happens in the partial events_detail.html. If I try to access the .Site from inside of the partial scope it renders a null. I also tried to pass it along on the (dict ...) but no lucky.
What Am I missing here?
I was missing how Hugo manage the scopes for the dot. You read a more in-depth explanation about this (and other important concepts) here:
https://regisphilibert.com/blog/2018/02/hugo-the-scope-the-context-and-the-dot/
In Resume is (extracted from the link above):
The root context, the one available to you in your
baseof.html and layouts will always be the Page context. Basically
everything you need to build this page is in that dot. .Title,
.Permalink, .Resources, you name it.
Even your site’s informations is stored in the page context with .Site
ready for the taking.
But in Go Template the minute you step into a function you lose that
context as your precious dot or context is replaced by the function’s
own… dot.
(...)
Same goes here, once you’ve opened an iteration with range the context
is the whatever item the cursor is pointing to at the moment. You will
lose your page context in favor of the the range context.
{{ range .Data.Pages }}
{{/* Here the dot is that one page 'at cursor'. */}}
{{ .Permalink }}
{{ end }}
Luckily Hugo stores the root context of a template file in a $ so no
matter how deeply nested you are within with or range, you can always
retrieve the top context. In basic template file, it will generally be
your page.
{{ with .Title }}
{{/* Dot is .Title */}}
<h1>{{ . }}</h1>
{{/* $ is the top level page */}}
<h3>From {{ $.Title }}</h3>
{{ end }}
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 }}
Is it possible to do some sort of eval in tornado templates?
Let me show an example of what I wish to do:
{% for c in columns %}
<!-- cdata is a dictionary, and columns is a list -->
<div class="cell"> {{ cdata[ {{ c }} ] }} </div>
{% end %}
e.g. I want to evaluate the current value in columns, and use it as a key to search in the cdata dictionary.
How do I do that?
Thanks
Expressions in Tornado templates cannot be nested, but they're just python expressions, which gives you the flexibility to do what you want. This includes calling the python eval if that's what you need, but it looks like in this case you simply need {{ cdata[c] }}.
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.