I am trying to do some basic arithmetic in Jekyll's liquid templating engine. I have assigned one variable numColumns and I am trying to use it in a conditional statement.
{% assign numColumns = 3 %}
Note I omitted the outer for loop in the below expression where loopindex comes from. Regardless, this works with the - operator and correctly evaluates to 2.
{% if loopindex == 3 - 1 %}
However, these alternatives I tried do not work:
{% if loopindex == numColumns - 1 %}
{% if loopindex == numColumns | minus: 1 %}
{% if loopindex == {{ numColumns }} - 1 %}
{% if loopindex == {{ numColumns | minus: 1 }} %}
How can I subtract one from numColumns in a conditional statement with the liquid templating engine?
You cannot use filter in liquid if expression.
You have to assign your calculation to a variable, then use it in your if tag.
{% assign calc = numColumns | minus: 1 %}
{% if loopindex == calc %}
Related
I'm trying to find a way to have the "if contains" conditions all appear in one line rather than having to repeat the code every single time.
Here is what the code looks like:
var selector = document.querySelector('tr[data-variant-id="{{ item.variant.id }}"] .product__description__variant');
{% assign pre_order_message = '' %}
{% for tag in item.product.tags %}
{% if tag contains 'weeks' %}
{% assign count = count | plus: 1 %}
{% assign pre_order_message = tag | split:'**' | last %}
var para = document.createElement("p");
para.classList.add('hc-shipping');
var node = document.createTextNode("Expected to begin shipping {{ pre_order_message }} from order date.");
para.appendChild(node);
selector.after(para);
{% endif %}
{% endfor %}
var selector = document.querySelector('tr[data-variant-id="{{ item.variant.id }}"] .product__description__variant');
{% assign pre_order_message = '' %}
{% for tag in item.product.tags %}
{% if tag contains 'January' %}
{% assign count = count | plus: 1 %}
{% assign pre_order_message = tag | split:'**' | last %}
var para = document.createElement("p");
para.classList.add('hc-shipping');
var node = document.createTextNode("Expected to begin shipping {{ pre_order_message }}.");
para.appendChild(node);
selector.after(para);
{% endif %}
{% endfor %}
I just want to make sure I can group together what lies between the ' ... ' on the line, that states {% if tag contains ' ' %}. Any way to fix? Thanks!
You can use and/or to combine conditions, more info about this here.
By the way if you just want to make sure a tag exists in product tags, you can do this:
{% if item.product.tags contains 'weeks' %}
Do something...
{% endif %}
Instead of looping through all the tags, you'll save a couple of lines that way ;)
One last thing, you can DRY the code by using code snippets, here's a quick read about this.
I'm trying to get my home.html layout to return a row for every forth column. But this keeps up giving me true everytime.
{%- if forloop.index0|modulo:4 == 0 -%}{%- endif -%}
Any ideas?
The problem with the above code is that Jekyll expects an end_of_string but found pipe in forloop.index0|modulo:4 == 0.
You have to assign the modulo calculation to a variable and then use it in the if clause, inside the for loop:
{% assign loopindex = forloop.index0 | modulo: 4 %}
{%- if loopindex == 0 -%}
<p style="background-color:red">Hey look! I'm a fourth element</p>
{%- endif -%}
I want to sort my Jekyll collections by the number of documents that are in each collection.
Each collection in the site.collections variable has a docs field, and the docs field (which is an array of documents) has a size field, which is the number of documents in this collection (see documentation).
However, something like this doesn't work:
{% assign sorted = site.collections | sort: 'docs.size' %}
{% for coll in sorted %}
...
{% endfor %}
It results in a
Liquid Exception: no implicit conversion of String into Integer
It seems that the argument to sort can only be an immediate field of the type of object being sorted, and not a field of a field thereof.
Is there a way to achieve sorting the collections by the number of documents they contain?
Build an array of the available sizes:
{% assign sorted = '' | split: "" %}
{% for coll in site.collections %}
{% assign sorted = sorted| append: coll.docs.size %}
{% endfor %}
Sort the above array.
Iterate the above array and all your collections printing only the collection whose size matches the sorted array number.
Ok, I achieved it in a rather ugly way, along the lines of marcanuy's answer.
<!-- Create a comma-separated string of all the sizes of the collections -->
{% for coll in site.collections %}
{% if coll.title %}
{% if coll.docs.size < 10 %}
{% assign str = coll.docs.size | prepend: "00" %}
{% elsif coll.docs.size < 100 %}
{% assign str = coll.docs.size | prepend: "0" %}
{% else %}
{% assign str = coll.docs.size %}
{% endif %}
{% assign sizes = sizes | append: str | append: "," %}
{% endif %}
{% endfor %}
<!-- Remove last comma of string -->
{% assign length = sizes | size | minus: 1 %}
{% assign sizes = sizes | slice: 0, length %}
<!-- Split string into array, sort DESC, and remove duplicate elements -->
{% assign sizes = sizes | split: "," | sort | reverse | uniq %}
<!-- Iterate through sizes, and for each size print those collections that have this size -->
{% for s in sizes %}
{% for coll in site.collections %}
{% assign i = s | plus: 0 %}
{% if coll.docs.size == i %}
<p>{{ coll.title }}: {{ i }} documents</p>
{% endif %}
{% endfor %}
{% endfor %}
The main difficulty is that an array of sizes created like this, is an array of strings, and sorting it results in an alphabetical sort order, rather than in an numerical one (e.g. "15" comes before "2").
To remedy this, I prepend "00" to numbers less than 10, and "0" to number less than 100. This makes the alphabetical sort order coincide with the desired numerical sort order.
Then I iterate through these sizes (which are still strings), and convert them to integers on the fly (by plus: 0) so that I can compare them to the docs.size field of each collection.
It's pretty verbose, but since this is executed only when the site is generated, and not at each request in production mode, it's ok.
Still, better solutions are welcome!
I would like to organize a page based on the number of pages that pass a filter.
I have tried to append truthy pages to a collection but it doesn't work.
{% assign homepage_posts = [] %}
{% for my_page in site.pages %}
{% if my_page.homepage %}
{% assign homepage_posts = homepage_posts | concat: [my_page] %}
{% endif %}
{% endfor %}
<h1>size{{homepage_posts.size}}</h1>
<h1>{{homepage_posts}}</h1>
This is not working. Does concat only work with strings?
Jekyll will use Liquid 4 soon. But, for now, no concat.
In your case you can :
Create an empty array (bracket notation doesn't work in liquid) : {% assign homepage_posts = "" | split:"/" %}
{{ homepage_posts | inspect }} --> output : []
And push elements in it :
{% for my_page in site.pages %}
{% if my_page.homepage %}
{% assign homepage_posts = homepage_posts | push: mypage %}
{% endif %}
{% endfor %}
{{ homepage_posts | inspect }}
concat filter only works with arrays and will be available in Jekyll when it upgrades to Liquid 4.*:
concat
Concatenates (combines) an array with another array. The resulting
array contains all the elements of the original arrays. concat will
not remove duplicate entries from the concatenated array unless you
also use the uniq filter.
To filter pages containing a specific attribute (in this case homepage: true) you can use a where filter.
Having a page with front matter:
---
homepage: true
---
Then you can have the pages with the homepage: true attribute like:
{% assign homepages = site.pages | where:"homepage","true" %}
To be clear, assuming:
{% assign my_var = "123" %}
{% assign another_var = "456" %}
I would like to append string to my_var to get something like 123 - 456
What I have tried so far:
{% assign my_var = my_var + " - " + another_var %}
You could use the capture logic tag:
{% capture new_var %}{{ my_var }} - {{ another_var }}{% endcapture %}
It is also possible to use the append filter, as Ciro pointed:
{% assign new_var = my_var | append: ' - ' | append: another_var %}
append: filter
This is more convenient than capture for short concatenations:
{% assign x = 'abc' %}
{% assign y = 'def' %}
{% assign z = x | append: ' - ' | append: y %}
{{ z }}
Output:
abc - def
Tested on jekyll 3.0.4 (github-pages 75).
All the answers so far are correct, but they fail to mention that you can also inline the append instead of having to assign a new variable:
Link