Does liquid markup have an "each with index" equivalent? - iteration

I need to loop through an array of items, alternating between two different background colors as I go. Is there a way to do this in liquid markup?

Let's say items contains ["a", "b", "c", "d", "e"], then something like this:
{% for item in items %}
{{forloop.index | modulo: 2}} -> {{item}}
{% endfor %}
would produce:
1 -> a
0 -> b
1 -> c
0 -> d
1 -> e

Related

what will be output of this shopify script?

<pre>
<!-- viewing /collections page with collection title of "A", "B", "C", "D" -->
{% assign colletion_titles = collections | map: 'title' %}
{{ colletion_titles }}
</pre>
What output would this liquid be?
The variable "colletion_titles" would be array.
All values will be printed like this:
ABCD
If you want to add commas between the titles, just add a | join: ", "
like this:
{{ colletion_titles | join: ", " }}

Shopify: How to check if there is > 1 collection in a cart

I am trying to prevent orders with more than one collection from being checked out. If there's more than one collection, i just want to disable the checkout button. I know the syntax is bad, but i want to do something like this.
{% for item in cart.collections %}
{% if item.collection.length > 1 %}
<button disabled>Cant checkout</button>
{% else %}
<button disabled>Can checkout</button>
{% endif %}
This is the current code for the button
<div class="cart__checkout-wrapper">
<button disabled id="button" type="submit" name="checkout" data-terms-required="{{ settings.cart_terms_conditions_enable }}" class="btn cart__checkout">
{{ 'cart.general.checkout' | t }}
</button>
{% if additional_checkout_buttons and settings.cart_additional_buttons %}
<div class="additional-checkout-buttons additional-checkout-buttons--vertical">{{ content_for_additional_checkout_buttons }}</div>
{% endif %}
</div>
{% endfor %}
Method 1
This simple check might work for what you need:
{% liquid
assign all_collections_in_cart = cart.items | map: 'product' | map: 'collections' | map: 'title' | uniq
assign collection_count = all_collections_in_cart.size
if collection_count > 1
assign can_checkout = false
else
assign can_checkout = true
endif
%}
What it does
First, we use a sequence of map filters to 'drill down' through the object structure. Items in the cart do not themselves belong to any specific collection(s), but each item is associated with both a variant and a product. From the product, we can then get all of the collections that it belongs to, which will be an array of collection objects. We can't do much with the objects themselves, so we drill down one layer further to get something that can be compared, such as title handle or id. At this point we now have an array of text entries (or numbers, if you swap to IDs), so we can apply the uniq filter to remove any duplicates.
Now that we have an array with no duplicates, we can check the size of the array to see if it is greater than one and set a variable appropriately.
Note that this will always return false if a single product belongs to more than one collection!
Method 2:
If instead you need to test that all products share a collection because products can belong to more than one at a time, we won't be able to take as many shortcuts. Instead, our code might look something like this:
{% liquid
assign can_checkout = true
if cart.items.size > 1
assign shared_collections = cart.items.first.product.collections | map: 'title'
for item in cart.items
if forloop.first
continue
endif
assign item_collections = item.product.collections | map: title
assign placeholder_array = ''
for coll in shared_collections
if item_collections contains coll
if placeholder_array.size > 0
assign placeholder_array = placeholder_array | append: ','
endif
assign placeholder_array = placeholder_array | append: coll
endif
endfor
assign shared_collections = placeholder_array | split: ','
if shared_collections.size == 0
assign can_checkout = false
break
endif
endfor
endif
%}
What it does
This second version will trigger if there are 2 or more items in the cart. If there are, we get all of the collection titles from the first item in the cart, then loop through all of the remaining items in the cart. At each step, we go through our list of shared collections to see how many are shared with the current item in the cart to make a new array. (Liquid does not let us make an array directly, so we have to build out a delimited string and then use the split filter afterwards)
If at any time we have an array with 0 shared entries, we set our can_checkout variable to false and use the break command to stop searching.
Addendum
For both of the above methods, things might get a little bit trickier if you have certain collections that don't count towards your collection rules. For example, if you have 'featured' or 'summer sale' collections, you will want to make sure that you aren't counting those in the collection comparisons (for example, by having an array of exceptions and removing those items from the array of collections that the item belongs to).

On Jekyll (Liquid) can't get where working

I have a people.yml like
- name: Foo
activities:
- title: bar1
- title: bar2
And an assign like
{% assign person = site.data.people | where: "activities.title", "bar1" %}
When I previously had only one activity per person (without having the title attribute) I could easily make it work. But now I'm struggling with it.
You cannot pass an Array to the where filter. It will not try to find the desired value by looping over all Hashes like {"title"=>"bar1"}, it will simply evaluate the property against the passed string. So, those Hash will never be equal to bar1.
My two cents :
Simplify people.yml by removing activities.name key :
Note : the two activities array presentations are equivalent.
- name: Foo
activities: [ bar1, bar2 ]
- name: Bar
activities:
- bar3
- bar4
You can now use the contains filter to retrieve people that have bar1 as an activity. contains filters strings or array like ["bar1", "bar2"]
{% assign selected = "" | split: "/" %} --> create empty array
{% for people in site.data.people %}
{% if people.activities contains 'bar1' %}
--> add people to array if match is found
{% assign selected = selected | push: people %}
{% endif %}
{% endfor %}

Referencing jinja2 variable from a variable

I want to be able to apply DRY and not have to repeat myself when building my jinja2 template. So I would like to be able to reference a variable within the jinja2 template from a dynamically constructed variable name, eg:
{% for a in [ 'a', 'b', 'c'] %}
{% set name = a + "_name" %}
{% set value = {{ name }} %}
hello there {{ value }}
{% endfor %}
where my input variables into jinja would be
a_name = 1
b_name = 2
c_name = 3
and I the result would be
hello there 1
hello there 2
hello there 3
is this possible?
I know i would just pass in a datastructure into jinja2 to do something similar, but I am not at liberty to modify what goes into the template.
i got the answer from here
basically, define a contextfunction and reference it within the jinja code:
from jinja2 import Environment, FileSystemLoader, contextfunction
j2_env = Environment( loader=FileSystemLoader(directory), trim_blocks=False )
this_template = j2_env.get_template( """
{% for i in [ 'a', 'b', 'c'] %}
hello there {{ context()[i+"_name"] }}
{% endfor %}
""" )
#contextfunction
def get_context(c):
return c
this_template.globals['context'] = get_context
this_template.render( **{ 'a_name': 1, 'b_name': 2, 'c_name': 3 } )

How can I use literal list in Django template file?

From a Django template file I want to check if my variable myVar is "A" or "B" (or "C" or "D", etc..).
So I would like to do something like this:
{% if myVar in ["A", "B"] %}
Hello
{% else %}
World
{% endif %}
But this gives me a syntax error in the first line.
How then can I use a literal list in the Django template file?
you can't define a list directly in the template. You could pass a list to the template using a view in views. py and a url in urls. py
ex:In views. py
def view_name(request):
list_name=['A', 'B', 'C'];
render(request, 'directory/template_name.html'
{'list_name':list_name})
In urls. py
urlpatterns = [
path('index/', views.view_name, name='main-view'),
]
In template
{% if myVar in list_name%}
Hello
{% else %}
World
{% endif %}
The answer can be found here: check for presence in a list django template
This question is essentially a duplicate.