Pass an Array to an include to loop over - jekyll

I have an include that can have >1 buttons depending on what is passed in.
Currently I have the following in the include:
{% if include.buttons %}
{% for button in include.buttons %}
<a class="{{ button.classes }}" href="{{ button.url }}">{{ button.title }}</a>
{% endfor %}
{% endif %}
Then I am trying to pass in the following data:
{% assign buttons = '[{ "title": "button 1", "url": "https://#", "classes": "btn btn-transparent" }, { "title": "button 2", "url": "https://#", "classes": "btn btn-primary" }]' %}
{% include header.html
buttons=buttons
%}
What I can't work out is how to pass the data correctly to the include so that I may loop through it.

The problem is the assignment of the data as a array. In liquid you can not directly initialize arrays. A workaround is to play with split.
However, using jekyll you can provide arrays via data files. Simply put your buttons in a file, say _data\buttons.yml with:
postXX:
- button1:
- title: "button 1"
- url: "https://#"
- classes: "btn btn-transparent"
- button2:
- title: "button 2"
- url: "https://#"
- classes: "btn btn-primary"
Now you could put a reference in the yaml-header of your post/page like:
---
your other yaml options....
buttons: postXX
---
Finally, assign the buttons and include them as you did in your code.
{% assign buttons = site.data.buttons[page.buttons] %}
{% include header.html
buttons=buttons
%}

With Liquid, you can't create an array with a literal expression like {% assign myArray = ["one","two","three"] %}.
You can only :
create empty one : {% assign emptyArray = "" | split: "" %}
create one from string : {% assign myArray = "one two three" | split: " " %}
You can then manipulate your array :
add an element to array : push or shift (jekyll specific filters)
remove an element from array : pop or unshift (jekyll specific filters)
merge two arrays with concat
and so on ...
So, your array can only come from a liquid array manipulation or some datas contained in configuration, data file or page front matter.

Related

Add json from static json file to index.twig with twig include

I'm struggling with json in twig. I want to include a static json file to my twig file and pass it to a twig include inside that.
I have my index twig file where I have my STATIC json file include and twig include:
{% set json %}
{% include "content.json" %}
{% endset %}
{% include '#partials/blocks/site-header.twig' with {json:json} %}
In My siteheader.twig I would like to render my navigation something like:
{% for headerNav in json %}
<a class="button button--nav" href="#">
{{headerNav.text}}
</a>
{% endfor %}
My content.json looks like this:
{
"headerNav":[
{
"text": "Link 1"
},
{
"text": "Link 2"
}
]
}
The whole point is that the siteheader should be able to render different links dependant on which json file i pass into it.

How to handle json dictionary in Liquid templates?

I am rather new to Liquid templates, but I don't seem to find a way to loop through a dictionary in json and access the different values.
Disclaimer: I am using the Shopify Liquid Preview extension for VSCode.
Input json file:
The input file contains two properties: CustomerId and Transactions, which is the 'dictionary' property, containing a list of KeyValuePairs. I want to loop through the Transactions collection and output the TransactionValue properties.
{
"CustomerId": 13,
"Transactions": {
"1": {
"Id": "1",
"TransactionValue": 1000
},
"2": {
"Id": "2",
"TransactionValue": 207.47
}
}
}
Expected output:
<h1>Customer 13</h1>
<ul>
<li>1000</li>
<li>207.47</li>
</ul>
Current Attempt
I can easily loop the collection, but then it's not clear to me on how I can access the actual properties of the current transaction. None of the following work. When just outputting the variable, it gets printed like this: 1,[object Object]
<ul>
{% for trx in Transactions %}
<li>{{trx}}</li>
<li>{{trx.Key}}</li>
<li>{{trx.Value}}</li>
<li>{{trx.Object}}</li>
{% endfor %}
</ul>
I don't really have control over the input json, so I was hoping to find a good way on making this work as is.
Thank you
In most Liquid flavors it should be possible to reference an object field by name like this:
{{ Transactions["1"].TransactionValue }}
Then it is a matter of getting all known transactionIds from somewhere. If they're not available as an array, then the dirty solution could be to parse raw incoming JSON, e.g. like that:
{% assign transactionIds = Transactions | split: "\"Id\": \"" %}
<ul>
{% for id in transactionIds %}
{% if id[0] != "{" %}
{% assign realId = id | split: "\"" | first %}
<li>
{{ Transactions[realId].TransactionValue }}
</li>
{% endif %}
{% endfor %}
</ul>

What Jekyll syntax to filter key:value pair in Front Matter?

In my Jekyll site, I have a page that stores an array of data in front matter, like this:
---
layout: page
title: MyTitle
array:
- key1: value1
- key2: value2
---
What I want to do in my template: given a keyX, obtain valueX from the array.
I figured out a way to access the array:
{% assign subpage = site.pages | where: 'title', 'MyTitle' %}
{% assign array = subpage[0].array %}
Now the query that I need to write is: "from the array, extract the value that matches keyX".
Is there a way to search through the array, without the need for looping? All the examples I can find are based on one-dimensional arrays...
Your array is an array of non standardized objects (they don't have the same keys).
{{ page.array | inspect }}
returns
[{"key1"=>"value1"}, {"key2"=>"value2"}]
Here the only way to search is to loop over all array's items.
If you refactor your array to become an object, you can then get value from a key.
---
[...]
object:
key1: value1
key2: value2
...
Example :
{% assign searched = "key1" %}
{{ page.object[searched] }}
I found this workaround in the meantime:
{% for valueList in array %}
{% for valuePair in valueList %}
{% if valuePair[0] == "key1" %}
{% assign value = valuePair[1] %}
{% endif %}
{% endfor %}
{% endfor %}

Find object by id in an array of JSON objects with Twig

I am being passed an array that unfortunately I cannot restructure:
"options": [
{"name":"namea","text":"valuea"},
{"name":"nameb","text":"valueb"},
{"name":"namec","text":"valuec"},
{"name":"named","text":"valued"}
]
I need to be able to find the object with the name equal to namea, nameb, namec, etc. and then produce the appropriate text. I tried the following and few other variations of that but could not get it to work:
{% for item in event.options %}
{% if item.name == "nameb" %}
{{ item.text|capitalize }}
{% endif %}
{% endfor %}
Thanks in advance for any help.
Edit: I basically only have access to a text box to input HTML and Twig. I do not have access to framework, custom extensions, etc.
Edit: JSON with exact formatting:
{
"source": "TEST.COM",
"trigger": "test",
"options": [{
"name":"test_date",
"value":"31-05-2017"
},
{
"name":"test_number",
"value":"9081003"
},
{
"name":"test_test",
"value":"9asd003"
},
{
"name":"Name",
"value":"Todd"
},
{
"name":"test_other",
"value":"kslkjsfd"
},
{
"name":"test_help",
"value":"908sdf3"
}]
}
This is going to be very hacky either way (I feel the javascript way as mentioned in the comments would still be less hacky).
However as its multilined we could write a basic parser like thing (this is by no means bullet proof and fails if the content has a ", or the structure changes or whatever changes to be honest):
{# create an array of lines #}
{% set event = event|split('\n') %}
{# an array to hold our options #}
{% set options = [] %}
{# using a bool to track if we are inside the options part #}
{% set inOptions = false %}
{# this holds the name of the last name value we have passed #}
{% set currentKey = '' %}
{# go through each line #}
{% for line in event %}
{# if we are inside the options tag do our magic #}
{% if inOptions %}
{# check if the line starts with "name": and track the current key name #}
{# or check if it starts with "value": and set the current key to that value #}
{% if line matches '/"name":/' %}
{# split line on the double quotes and get the last bit #}
{% set currentKey = line|split('"') %}
{# cant get the array index piped in one go idk.. #}
{% set currentKey = currentKey[3] %}
{% elseif line matches '/"value":/i' %}
{% set currentValue = line|split('"') %}
{% set options = options|merge({(currentKey): currentValue[3]}) %}
{% elseif line matches '/\s*}]/' %}
{% set inOptions = false %}
{% endif %}
{% endif %}
{# check for the options sectioning start #}
{% if line matches '/^"options/' %}
{% set inOptions = true %}
{% endif %}
{% endfor %}
{{ dump(options) }}
This returns in my dump (which you didn't have so you cant see):
array:6 [▼
"test_date" => "31-05-2017"
"test_number" => "9081003"
"test_test" => "9asd003"
"Name" => "Todd"
"test_other" => "kslkjsfd"
"test_help" => "908sdf3"
]
As an actual array where you can then call options.test_date but all this is super hacky, it still can be improved but twig is not made for it and the syntax gets so clunky its hard to maintain.

Comparing variables in template to build JSON - Ansible

Starting off with Ansible and I am trying to use ReST API to interact with an external application.Maybe I am missing something simple here.
I am trying to compare every host in my inventory file with the POD name specified in the variable file used by the role that invokes the jinja2 template.
My inventory file looks like this:
[all]
'POD-9'
'POD-10'
Variable file :
pods:
params:
- name: POD-9
- name: POD-10
{% for pod in pods.params %}
{% if '{{ inventory_hostname }}' == '{{ pod.name }}' %}
<generate JSON template here>
{% endif %}
{% endfor %}
The if statement however does not take effect. I want the template to be generated only in the inventory_hostname is equal to the pod name in the variable file
The current JSON file includes both :
{
"pod": {
"name": "POD-9"
}
"pod": {
"name": "POD-10"
}
}
In Jinja2 the double curly braces are used as a print statement. If you access variables inside tags don’t put the braces around them
{% for pod in pods.params %}
{% if inventory_hostname == pod.name %}
<generate JSON template here>
{% endif %}
{% endfor %}
Found the problem :
{% if pod.name == inventory_hostname %}