How to sort YAML using Jekyll Liquid - loops

I have the following YML code that I am trying to sort alphabetically in Jekyll:
layout: project
title: Home renovation
link: http://urlgoeshere.com
builtWith:
- Concrete
- Glass
- Brick
- Dirt
Here is my template code:
<h4>Built With</h4>
<ul class="list-unstyled list-inline list-responsibilities">
{% for item in page.builtWith %}
<li>{{ item }}</li>
{% endfor %}
</ul>
What do I need to add to the for loop to get the builtWith items to sort alphabetically?
Thanks!

Try this
{% assign sorted = (page.builtWith | sort) %}
{% for item in sorted %}

In the latest Jekyll version, using just sort tag doesn't work because you need to assign it to a variable first: Liquid Warning: Liquid syntax error (line 24): Expected end_of_string but found pipe in "item in page.builtWith | sort".
If you are not using the latest version then it can work adding sort in the same line.
Using assign and sort tags is safer:
<h4>Built With</h4>
<ul class="list-unstyled list-inline list-responsibilities">
{% assign sorted = page.builtWith | sort %}
{% for item in sorted %}
<li>{{ item }}</li>
{% endfor %}
</ul>
Outputs:
Built With
Brick
Concrete
Dirt
Glass

Related

Jinja2 - If condition & nested array

I'd like to build to simple if logic into my Jinja2 template with nested arrays.
Firstly, including my vars for reference.
In YML (from host_vars):
interfaces:
- name: ae10
ipv4:
- address: 4.4.4.4
mask: 8
in JSON (from Ansible debug):
"interfaces": [
{
"ipv4": [
{
"address": "4.4.4.4",
"mask": 8
}
],
"name": "ae10"
}
],
I would like the if statement to make sure that ipv4.address and ipv4.mask have values. The only way I seem to be able to do it at the moment, is to map the nested array first, and then run if statement. But I'm wondering if the if statement can be ran earlier? Like even before the for loop starts?
{%for interface in interfaces%}
{%for ip in interface.ipv4%}
{% if ip.address and ip.mask%}
matched {{ip.address}}/{{ip.mask}} on {{interface.name}}
{% else %}
nothing matched
{% endif %}
{%endfor%}
{%endfor%}
It might, or might not be possible - and I might be missing something silly. Your thoughts would be greatly appreciated.
Q: "Can the if statement be run earlier? Like even before the for loop starts?"
A: No. It's not possible. It's possible to omit items that don't comply with the conditions, create a new dictionary, and process the new dictionary.
The task below is testing in the loop
- debug:
msg: "matched {{ item.1.address }}/{{ item.1.mask }} on {{ item.0.name }}"
loop: "{{ interfaces|subelements('ipv4') }}"
when:
- item.1.address is defined
- item.1.mask is defined
gives
"msg": "matched 4.4.4.4/8 on ae10"
Conditional output can be achieved also with the template below
{% for item in interfaces %}
{% for ip in item.ipv4 %}
{% if ip.address and ip.mask%}
matched {{ ip.address }}/{{ ip.mask }} on {{ item.name }}
{% else %}
nothing matched
{% endif %}
{% endfor %}
{% endfor %}

Print whitespace within jinja loop

I am trying to print the list of hosts in an ansible task;
I want to have spaces among them, however the following loop does not achieve the purpose:
{% for host in groups['all'] -%} {{ host }}:6379 {%- endfor %}
Any suggestions?
If you're aiming to get them all on a single line and don't mind having a space at the start you could simply do:
{% for host in groups['all'] -%} {{ ' ' ~ host }}:6379 {%- endfor %}
You could also add a character to the end of each item (e.g space or something else), while skipping the last one. Note the space between the if and endif:
{% for host in groups['all'] -%}
{{ host }}:6379
{%- if not loop.last %} {% endif %}
{%- endfor %}
As an alternative to the jinia loop, you could use ansibles join-filter, see in https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#id8
in this case :
{{ groups["all"] | join(":6379 ") }}
Join is the opposite for split. split takes a string and a delimiter and then return a list. join takes a list and a string to concatenate all list-elements to one string.

collections pages loop not working on github

Jekyll Version: 2.4.0
github pages Version: 35
My Reproduction Steps
Build on locally and the looping of collections site.collections.guides.docs shown, generated the correct .html in _site folder as well.
However, when I deploy to github, it doesn't show the loop content.
The Output I Wanted
shown the loop in github pages, appreciate if someone have a look on my repo.
my codes:
// index.html
{% for doc in site.collections.guides.docs %}
{{ doc.content }}
{% endfor %}
// _config.yml
collections :
guides:
output: true
I would write it like this:
{% for doc in site.guides %}
{{ doc.content }}
{% endfor %}
And the config like this:
collections:
guides:
output: true

Symfony2 - Checking if an image type exists

I've been following an earlier post to check if an asset exists, which works great when using specific filenames.
Symfony2 and Twig - Check if an asset exists
However instead of checking for a specific image filename, how do you check for an image type? (all files with the .jpg extension)
Example: *.jpg (which doesn't work neither does .jpg)
{% if asset_exists('/images/*.jpg') %}
<div class="entry-thumbnail">
<img width="230" height="172" src="{{ asset(['images/', post.image]|join) }}" class="" alt=""/>
</div>
{% endif %}
As soon as you are using:
{{ asset(['images/', post.image]|join) }}`
Why not using:
{% if asset_exists(['images/', post.image]|join) %}
Tip: replace ['images/', post.image]|join by using the concat operator ~: 'images/' ~ post.image
You'd have to modify the Twig Extension and replace !is_file($toCheck) with count(glob($toCheck)) < 1
glob function (php.net)

Can I create an runtime-array with values somehow?

I am trying to create a sidebar-menu that looks like this.
iOS
-entry1
-entry2
-entry3
Web
-entry1
-entry2
Other
-entry1
-entry2
Each "post" (as in - the files in the dir "_posts") will have one (or more) categories in the meta-data (at the top of the file) and is to be listed underneath that header in the menu. So for example, if I make a post which has got "categories: iOS" it should be listed under the "iOS" header in the menu.
{% for cat in ["jekyll","ios","test"] %} // This is what I am unable to get right
{% for post in site.posts %}
{% if post.category == cat %}
{{ post.categories }} // test
<li>{{ post.title }}</li>
{% endif %}
{% endfor %}
{% endfor %}
Is it not possible to create an array on the fly like this? I am finding it really hard to google this specific question I have.
Alright to create an array on the current page I needed to use "front matter" i.e. the things on top of the pages surrounded by "---"
This is the solution:
Top of page:
---
cats: [1,2,3,asd]
---
Further down:
{% for c in page.cats %}
{{c}}<br/>
#loop through more here.
{% endfor %}
</body>

Resources