How to handle json dictionary in Liquid templates? - json

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>

Related

Shopify Looping Over JSON Metafield Arrays

For some reason, I can't access an array within a JSON metafield.. I've tried the other StackOverflow answers, and I'm using value, etc. but just can't figure it out, here's my metafield:
product.metafields.artist.releases
with a value of:
{
  "releases": [
   { 
"id": 0,
    "releaseName": "lofi 1",
    "coverArt": "",
    "releaseLink": “”
},
 { 
"id": 1,
    "releaseName": " lofi 2",
    "coverArt": "",
    "releaseLink": “”
}
]}
(which formats to: "{\"releases\":[{\"id\":0,\"releaseName\":\"lofi 1\",\"coverArt\":\"\",\"releaseLink\":“”},{\"id\":1,\"releaseName\":\"lofi 2\",\"coverArt\":\"google.com\",\"releaseLink\":“”}]}")
and I'm using this in the product.custom.liquid:
{{ product.metafields.artist.releases.value }}
{% assign releases = product.metafields.artist.releases.value %}
{% for release in releases.releases %}
{{ release.releaseName }}
{% endfor %}
the first one shows up fine, and if I assign it and do {{ releases }} it shows up fine as well so I know the assignment is working, but I can't forloop over it (mind you that the first object in the JSON is also called releases (I've also tried renaming it all to unique names just in case and that didn't help))
For some reason when it is a multidimensional JSON array it acts weird. There is a simple fix for it, just add (-) at the end of your assigned variable:
{%- assign releases = product.metafields.artist.releases.value -%}
{% for release in releases.releases %}
{{ release.releaseName }}
{%- endfor -%}
Hope it solves your problem like it did mine!
Liquid is not going to work on JSON like this. If you want to iterate through an array of JSON objects, use Javascript.
As lov2code points out by adding (-) it trims the output for any unnecessary white space, which enables you to traverse the JSON array.

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 %}

Pass an Array to an include to loop over

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.

Django: how to loop through nested Json object in html

I am new to json, and I have a nested json object called jresult in django view.py. I passed this object to html and I wanna display it in html.
in view.py:
return render(request,'home.html', {'jresult': jresult})
jresult:
{
"company": "xxx",
"address": "xxx",
"ceo": "xxx,
"employee": {
"Emily": {
"id": "xxx",
"gender": "xxx"
},
"Tom": {
"id": "xxx",
"gender": "xxx"
},
"Alex": {
"id": "xxx",
"gender": "xxx"
},
},
}
So far I can only loop through the employee's name and display them in the html page: Emily, Tom and Alex by the following html code:
{% for obj in jresult.employee %}
<p>{{obj}}</p>
{% endfor %}
how can I access the id and gender as well, I have tried
{% for obj in jresult.employee %}
<p>{{obj}}</p>
{% for item in jresult.employee.obj.gender %}
<p>{{item}}</p>
{% endfor %}
{% endfor %}
but it doesn't work.
Any helps will be appreciated.
Take a look at this (similar request) or (if it don't work) you can implement your own filter to transform the json in the desired form
Edit:
Basically you can try
{{ jresult['employee'] }}
because as cited in the first link, you have dictionaries in the json
JSON is a nested structure so you should be able to access attributes of relative objects using a simple dot notation. You must have the employee field as an array, not an object, if you want to iterate through them like so:
Try this:
{% for obj in jresult.employee %}
<p>{{obj}}</p>
<p>{{obj.id}}</p>
<p>{{obj.gender}}</p>
{% endfor %}
You can do {{ jresult['employee']['Emily'] }} and then use dot notation to print the remaining
{{ jresult['employee']['Emily'].gender }}
That should print the gender if I am not mistaken. However this is not maintainable as it requires you to know the names of each key before printing.
Django templates should allow you to do something like this, as json should be treated as python dictionary.
{% for employee_key, employee_value in jresult.employee %}
<p>{{employee_key}}:{{employee_value}}</p>
{% endfor %}
Reference: https://docs.djangoproject.com/en/2.0/ref/templates/builtins/#for
Asides from this - I would probably just write a serializer/transformer to change this data into template readable before sending it to the front-end.
Hope this helps!

How to load data from JSON in Jekyll

While exploring Jekyll for site generation I faced with a JSON data loading problem. I've generated default Jekyll site, added tracks.json file to _data folder and added this code to default index.html
<span>Tracks:</span>
<ul>
{% for track in site.data.tracks.tracks %}
<li>Title: {{ track.title }}</li>
{% endfor %}
</ul>
In a result I've got this code generated:
<span>Tracks:</span>
<ul>
</ul>
tracks.json looks like:
{
"tracks":[
{
"id":"140",
"title":"Android"
},
{
"id":"142",
"title":"GDG[x]"
}
]
}
Am I using the right way to access JSON fields? If not, what is the right way?
UPDATE: issue was fixed in Jekyll v.2.1.0
You can make your top-level element in the .json file an array like this:
[{
"id":"140",
"title":"Android"
},
{
"id":"142",
"title":"GDG[x]"
}]
Then you can access it more simply like this {% for track in site.data.tracks %}.
Try it by site.data.tracks[0].tracks. Have a good time. ;-)
I would suggest to put your data in track.json like this:
{
"atribut": "Jekyll site generation with JSON data",
"gallery":[
{
"group":"Tracks",
"items":[
{
"id":"140",
"title":"Android"
},
{
"id":"142",
"title":"GDG[x]"
}
]
}
]
}
You may put other attributes as many as you like and access the data like this:
{% for product in site.data.track.gallery %}
<span>{{ product.group }}:</span>
<ul>
{% for item in product.items %}
<li>Title: {{ item.title }}</li>
{% endfor %}
</ul>
{% endfor %}
The output will remain be the same as expected:
<span>Tracks:</span>
<ul>
<li>Title: Android</li>
<li>Title: GDG[x]</li>
</ul>
The benefit is that you are free to justify that JSON file at any time without disturbing the data.
I really recommend to use yaml instead :) . It's natively supported by Jekyll (you can put it in _config.yml (then you can use it in many pages) or in page's YAML Front matter (then it's available to the page itself). When you put it there, the data is parsed by jekyll and you can use it directly from there.
You can even convert your Json to Yaml fairly easily:
https://www.npmjs.org/package/json2yaml
And Yaml is quite nice format, in some ways even better than JSON