Access nth value of Array in Nunjucks - nunjucks

I would like to access the second value of an array in Nunjucks. Is this possible? I've read through the documentation but I can't seem to work it out.
{{ array | first }} and {{ array | last }} work, but is it possible to do something like {{ array | second }} ?

Just to solidify Aikon Mogwai's comment, you can do this with bracket notation on the array itself like this:
var data = { arr: ['a','b','c'] }
var templateStr = "{{ arr[1] }}"
var result = nunjucks.renderString(templateStr, data) // 'b'
Demo in CodePen

Related

Changing a html class after the first item in a Hugo loop

So I am making a review carousel using Bootstrap and Hugo, I've got code that breaks down into this:
{{ range seq 1 3 (len site.Data.reviews) }}
...
{{ range seq . (add . 2) }}
{{ with (index site.Data.reviews (string .)) }}
{{ .des }}
{{ end }}
{{ end }}
...
{{ end }}
So there's two loops, one to make the slides for the carousel, and the other to fill the slides with data files. The issue is I need to delete the active class and adjust the data-bs-interval input on the next few slides I thought about making an if statement but I'm not sure how to replace the first div with one that doesn't have the active class after that in whats generated.
I don't know if this is the best solution to it, instead of editing the loop I wrote a bit of javascript:
var addActive = document.getElementById('carouselExampleDark').getElementsByClassName('carousel-item')[0];
addActive.classList.add("active");
That works for my use case so I'll leave it at that.

How to create array template in Ansible?

I have a template file config.j2:
{% for host in groups['dbs'] %}
ips= {{ hostvars[host].ansible_default_ipv4.address }}
{% endfor %}
My output is:
ips= 192.168.231.91
ips= 192.168.231.92
ips= 192.168.231.93
I want save in array variable like this:
ips=['192.168.231.91','192.168.231.92','192.168.231.93']
How can do this?
Solution
ips=[{{ groups['dbs'] | map("regex_replace", "(.*)", "'\\1'") | join(",") }}]
Explanation
Strings ips[ and ] are printed directly in the template;
The Jinja2 expression processes the groups['dbs'] list:
map filter applies a filter (regex_replace) to individual elements of the list;
regex_replace filter surrounds each list element (string) in single quotes;
join filter converts the resulting list to comma-delimited string in the output.

How to get a field by index in template?

I send a slice of articles into template. Each articlestruct is like:
type Article struct {
ID uint32 `db:"id" bson:"id,omitempty"`
Content string `db:"content" bson:"content"`
Author string `db:"author" bson:"author"`
...
}
I can loop over articles slice in a {{range $n := articles}} and get each {{$n.Content}} but what I want is to have only the first one (outside the range loop) to use in headline.
What I tried is:
{{index .articles.Content 0}}
But I get:
Template File Error: template: articles_list.tmpl:14:33: executing
"content" at <.articles.Content>: can't evaluate field Content in type
interface {}
If I just invoke
{{index .articles 0}}
It shows the whole article[0] object.
How can I fix this?
The index function access the nth element of the specified array, so writing
{{ index .articles.Content 0 }}
is essentially trying to write articles.Content[0]
You would want something akin to
{{ with $n := index .articles 0 }}{{ $n.Content }}{{ end }}
A more concise way is:
{{(index .articles.Content 0).Content }}
Which would be the equivalent of articles[0].Content.
{{(index .articles 0).Content}}

Golang: Ordering map by slice in Go templates

I have a question about how to order a map by a slice in Go Templates and if it is possible.
Problem: I have a slice of ordered variable names that I want to display on a website, accompanying them I have a map of metadata of variable information that I would like to display together with the variable.
If I have the following struct that I pass in to the template:
type Data struct {
Variables []string
Information map[string]int
}
I would iterate over the slice and pass the variable name in to the map
{{ range $v := .Variables }} {{ index .Information $v }} {{ end }} // Doesn't work.
Here's a Go Playground with the example.
https://play.golang.org/p/AL2csnXdoU
Question: How can I do this?
I am fairly new to Golang. Thankful for any input.
The following should work. To access .Information inside range, you should use $, which is basically d in your Playground example.
{{ range .Variables }} {{ index $.Information . }} {{ end }}

How to concatenate strings in twig

Anyone knows how to concatenate strings in twig? I want to do something like:
{{ concat('http://', app.request.host) }}
This should work fine:
{{ 'http://' ~ app.request.host }}
To add a filter - like 'trans' - in the same tag use
{{ ('http://' ~ app.request.host) | trans }}
As Adam Elsodaney points out, you can also use string interpolation, this does require double quoted strings:
{{ "http://#{app.request.host}" }}
Also a little known feature in Twig is string interpolation:
{{ "http://#{app.request.host}" }}
The operator you are looking for is Tilde (~), like Alessandro said, and here it is in the documentation:
~: Converts all operands into strings and concatenates them. {{ "Hello
" ~ name ~ "!" }} would return (assuming name is 'John') Hello John!. – http://twig.sensiolabs.org/doc/templates.html#other-operators
And here is an example somewhere else in the docs:
{% set greeting = 'Hello' %}
{% set name = 'Fabien' %}
{{ greeting ~ name|lower }} {# Hello fabien #}
{# use parenthesis to change precedence #}
{{ (greeting ~ name)|lower }} {# hello fabien #}
In this case, where you want to output plain text and a variable, you could do it like this:
http://{{ app.request.host }}
If you want to concatenate some variables, alessandro1997's solution would be much better.
{{ ['foo', 'bar'|capitalize]|join }}
As you can see this works with filters and functions without needing to use set on a seperate line.
Whenever you need to use a filter with a concatenated string (or a basic math operation) you should wrap it with ()'s. Eg.:
{{ ('http://' ~ app.request.host) | url_encode }}
You can use ~ like {{ foo ~ 'inline string' ~ bar.fieldName }}
But you can also create your own concat function to use it like in your question:
{{ concat('http://', app.request.host) }}:
In src/AppBundle/Twig/AppExtension.php
<?php
namespace AppBundle\Twig;
class AppExtension extends \Twig_Extension
{
/**
* {#inheritdoc}
*/
public function getFunctions()
{
return [
new \Twig_SimpleFunction('concat', [$this, 'concat'], ['is_safe' => ['html']]),
];
}
public function concat()
{
return implode('', func_get_args())
}
/**
* {#inheritdoc}
*/
public function getName()
{
return 'app_extension';
}
}
In app/config/services.yml:
services:
app.twig_extension:
class: AppBundle\Twig\AppExtension
public: false
tags:
- { name: twig.extension }
In Symfony you can use this for protocol and host:
{{ app.request.schemeAndHttpHost }}
Though #alessandro1997 gave a perfect answer about concatenation.
Quick Answer (TL;DR)
Twig string concatenation may also be done with the format() filter
Detailed Answer
Context
Twig 2.x
String building and concatenation
Problem
Scenario: DeveloperGailSim wishes to do string concatenation in Twig
Other answers in this thread already address the concat operator
This answer focuses on the format filter which is more expressive
Solution
Alternative approach is to use the format filter
The format filter works like the sprintf function in other programming languages
The format filter may be less cumbersome than the ~ operator for more complex strings
Example00
example00 string concat bare
{{ "%s%s%s!"|format('alpha','bravo','charlie') }}
--- result --
alphabravocharlie!
Example01
example01 string concat with intervening text
{{ "The %s in %s falls mainly on the %s!"|format('alpha','bravo','charlie') }}
--- result --
The alpha in bravo falls mainly on the charlie!
Example02
example02 string concat with numeric formatting
follows the same syntax as sprintf in other languages
{{ "The %04d in %04d falls mainly on the %s!"|format(2,3,'tree') }}
--- result --
The 0002 in 0003 falls mainly on the tree!
See also
http://twig.sensiolabs.org/doc/2.x/filters/format.html
https://stackoverflow.com/tags/printf/info
To mix strings, variables and translations I simply do the following:
{% set add_link = '
<a class="btn btn-xs btn-icon-only"
title="' ~ 'string.to_be_translated'|trans ~ '"
href="' ~ path('acme_myBundle_link',{'link':link.id}) ~ '">
</a>
' %}
Despite everything being mixed up, it works like a charm.
The "{{ ... }}"-delimiter can also be used within strings:
"http://{{ app.request.host }}"

Resources