{{ TWIG }} Define Dynamic Array Name - arrays

I am using {{TWIG}} with the Shopwired Platform. Hard coded into one of the templates is a gallery;
{# Render carousel #}
{% set gallery_name = 'global.theme.settings.gallery_location %}
This of course is working and great, however I would like to extend upon this and make some dynamic galleries for the site I am building.
I have figured out how to append/prepend the page title to build this;
{# Render carousel #}
{% set gallery_name = 'global.theme.settings.gallery_' ~ title|lower %}
{% set images = gallery_name %}
When I use {{ images }} to echo the result, it outputs the string name 'global.theme.settings.gallery_location' (which is correct for the page I am on) and not 'Array' as expected and desired.
The following, must be nearly right, but it only outputs one item from the array..
{# Render carousel #}
{% set gallery_name = 'global.theme.settings.gallery_' ~ title|lower %}
{% set images = [gallery_name] %}
I'm close.. what am I doing wrong?

To use dynamic keys, u can't relate on the dot notation to acces properties as the compiler can't handle that. Either use attribute or the array notation to access the data.
{% set arr = {
foo : {
bar : {
foobar : {
dynamic_index : 42,
}
}
}
} %}
{% set key = 'dynamic' %}
{{ attribute(arr['foo']['bar']['foobar'], key~'_index') }} {# 42 #}
{{ arr['foo']['bar']['foobar'][key~'_index'] }} {# 42 #}

Related

HubL / Twig: Not finding value from array

In HubSpot, I've created a custom module called footer. footer has five field types of menu:
I've created an array where all five of the above menu ID's are pushed to an array. I've done this via a template partial file which is included in my footer module.
<!-- creating array -->
{% set footer_id_array = [] %}
<!-- push menu id's to array -->
{% do footer_id_array.append(module.menus.menu_column_1) %}
{% do footer_id_array.append(module.menus.menu_column_2) %}
{% do footer_id_array.append(module.menus.menu_column_3) %}
{% do footer_id_array.append(module.menus.menu_column_4) %}
{% do footer_id_array.append(module.menus.menu_column_5) %}
Running {{ footer_id_array }} shows all the IDs in the array, i.e.
[29420054435, 29420223163, 29420054590, 29420158158, 29420071857]
So this is correct, the array contains the IDs.
Now, for each item in this array, I want to generate a nav, so in my footer custom module, I have the following:
{% set iterations = range(0, 5) %}
{% for i in iterations %}
<nav>
{% menu id="{{ footer_id_array[i] }}" %}
</nav>
{% endfor %}
However, on my page, this just prints HubSpots default menus, not the ones assigned to the ID's.
Why is this?

Jinja2 set variable string outside loop without namespace

I am trying to create a concatenated string off a loop and then set this to a variable I can then use outside the loop. I don't have access to namespace I am using an older version of Jinja2.
Here is what I have so far to illustrate what I am trying to do...
{% set ab_cart_string = '' %}
{% for item in cart_object %}
VariantID = {{ item.variant_id }}
Item Count = {{ item.quantity }}
{% set ab_cart_string = ab_cart_string ~ item.variant_id ~ ':' ~ item.quantity ~ ',' %}
String = {{ ab_cart_string }}
{% endfor %}
Url = {{ ab_cart_string|slice(0, -1) }}
Expected Output:
String = 27707915206755:1,28410722943075:1,
Url = 27707915206755:1,28410722943075:1
Actual Output:
String = 27707915206755:1,28410722943075:1,
Url =
Instead of accessing variables outside the loop I built the string inside an tag as the goal was to build a link.
Here I am looping through the products object and through each index I am adding a variant.id and a quantity to manually build a cart link in Shopify with the items that were last added from a user.
Then when there are multiple items in the loop I added a condition if not last loop we need to add a comma between the indexes. This way I was able to build the link properly per the permalinks to pre-load the cart in Shopify.
<a href="https://{{ event.domain }}/cart/
{%- set products = cart_object -%}
{%- for product in products -%}
{{- product.variant_id -}}:{{- product.quantity -}}
{%- if not loop.last -%},{%- endif -%}
{%- endfor -%}
">CART LINK HERE</a>

looping over jekyll collections

I have the following code
<div>
{% for note in site.regnotes %}
{% if note.regulationno == page.regulationno %}
<p>
{{ note.regulationno }} - {{ note.url }}
</p>
{% endif %}
{% endfor %}
</div>
This code loops over the regnotes collection in a jekyll site, checks if the current note regulationno is the same as the page regulationno and if so displays the regulationno and url - that is the url of the current page. How do I change this code to include the url of the previous page, the current page and the next page. I'm looking for three urls - previous, current and next? - The "page.previous.url" variable within jekyll does not appear to work in collections.
This is what it might look like in other code
for i=1 to number of items in the regnotes collection
if current note == page note
print page[i].url //current page url
print page[i-1].url //previous page url
print page[i+1].url //next page url
end if
end for
I suppose what I'm trying todo is reference the items in the collection by their array index. just can't seem to get the syntax correct.
Since you are a programmer, you just need to know that you need to use forloop.index0 to know where you are in the for loop (https://docs.shopify.com/themes/liquid-documentation/objects/for-loops#index0).
The code will be something like:
<div>
{% for note in site.regnotes %}
{% assign current_index = forloop.index0 }}
{% assign next_index = current_index | plus: 1 %}
{% assign prev_index = current_index | minus: 1 %}
{% if note.regulationno == page.regulationno %}
<p>
{{ note.regulationno }} - {{ note.url }}
</p>
{% if site.regnotes[prev_index] %}prev{% endif %}
{% if site.regnotes[next_index] %}next{% endif %}
{% endif %}
{% endfor %}
</div>

django template tags, work with an array output

I created a tag which output is an array:
from django import template
register = template.Library()
def create_array(context):
output=[1,2,3,4]
return output
register.simple_tag(takes_context=True)(create_array)
When I call this tag in the template: {% load create_array %} {% create_array %}, the array is printed, but I can't access to each element in this way:
{% load create_array %}
{% for i in create_array %} {{i}} {% forend %}
Any idea how can I access to each element?
The error is during template rendering: Exception Value: 'create_array' object is not iterable.
PS: I need "context" in the tag, so I just wrote a short example. I'm using Django version 1.6.2
#laffuste has a good point that you need to use the as command to store the array into a template variable before you iterate through it. However, there's a slightly neater way to write the tag -- this is, in fact, precisely what Assignment Tags were made for:
from django import template
register = template.Library()
#register.assignment_tag(takes_context=True)
def create_array(context):
return [1,2,3,4]
That's it -- the assignment tag does the nasty work of parsing and return a template-variable-friendly output. Everything in laffuste's answer for the template is exactly what you'd need, but just so you can have it all in one place, here it is reproduced again so it's all in one place:
{{ load my_custom_tags }}
{% create_array as my_array %}
{% for item in my_array %}
{{ item }}
{% endfor %}
To get an index of each object in the forloop, use a forloop.counter like so:
{% load create_array %}
{% for i in create_array %}
{{ forloop.counter }}
{% forend %}
If you want to do something when you hit a certain count in the forloop, then use the following code:
{% for i in create_array %}
{% if forloop.counter == 1 %}
Do something with {{ i }}.
{% endif %}
{% endfor %}
Here is the Django Documentation for the forloop counter:
https://docs.djangoproject.com/en/dev/ref/templates/builtins/#for
I'm afraid there's no simpler way than...
from django import template
from django.template.base import TemplateSyntaxError
register = template.Library()
#register.tag(name='create_array')
def create_array(parser, token):
class ArrayCreator(template.Node):
def __init__(self, var_name):
self.var_name = var_name # output variable
def render(self, context):
context[self.var_name] = [1, 2, 3, 4] # access to context
return ''
args = token.contents.split() # "create_array", "as", VAR_NAME
if len(args) != 3 or args[1] != 'as':
raise TemplateSyntaxError("'create_array' requires 'as variable' (got %r)" % args)
return ArrayCreator(args[2])
Usage in Template:
{{ load my_custom_tags }}
{% create_array as my_array %}
{% for item in my_array %}
{{ item }}
{% endfor %}
But maybe someone will come with something lighter and nicer?

How to populate an array of array in Twig?

I have a problem with an array of arrays in Twig.
Here is the code I am struggling with :
{% set tabTmp = {0:{},1:{},2:{},3:{},4:{},5:{},6:{},7:{},8:{}} %}
{%for element in box.elements%}
{% set tab = tabTmp[element.category.id] %}
{% set elementId = element.id %}
{% set tab = tab | merge({elementId:element}) %}
{% endfor%}
{%for key, tmp in tabTmp %}
{% if tmp is iterable %}
{{ dump(tmp) }}
{% endif %}
{% endfor%}
box.elements and element exist, element.category.id and element.id are integer and element is the object I want to work with.
But I keep having Array(0) as a result of dump(tmp).
Any ideas ?
Everything looks fine, but if you want to merge a variable as key to an associative array you need to use ();
so try changing
{% set tab = tab | merge({elementId:element}) %}
To
{% set tab = tab | merge({(elementId):element}) %}

Resources