How to iterate and retrieve from YAML _data in Jekyll? - arrays

I'm trying to build a Jekyll blog. But I never used YAML before and I'm going mad with the logic of this thing.
First I wrote a YAML file in _data/authors.yml with a list of authors and their respective meta-info:
- authors:
- user: andre
name: Andre Santos
site: http://test.dev
email: andre#test.dev
- user: john
name: John Doe
site:
email: john.doe#test.dev
Now I want to do two very simple things: first, to iterate over all authors, displaying some info about them:
{% for list in site.data.authors %}
{% for author in list %}
{{ author.user }} - {{ author.user.name }}
{% endfor %}
{% endfor %}
But it shows nothing!
Now in some other part of the code I just want to retrieve info from a specific user:
{% assign the_user = site.data.authors.authors[post.username] %}
{{ the_user.name }}
And, once again it shows nothing! I have no idea what I'm doing wrong, I tried lots of other solutions, iterations, but I can't make heads or tails about how to iterate YAML files, and I don't know Ruby so most of the solutions I found in this site don't work for me when I adapt them into Jekyll + Liquid.
What am I doing wrong? How to access those variables?

Problem solved!
After some long deliberation, I got a very simple solution, based on 2 steps: change from YAML to JSON, and then understanding Jekyll returns a Ruby Hash instead of an array.
So, the final file, authors.json:
{
"andre": {
"name": "Andre Santos",
"site": "http://test.dev",
"email": "andre#test.dev"
},
"john": {
"name": "John Doe",
"site": "",
"email": "john.doe#test.dev"
}
}
Now that the file is corrected, let's take care of selecting one of its items and showing it.
{{ site.data.authors[post.author].name }}
If post.author = "andre", the template will return Andre Santos. First problem, solved!
Now, Jekyll is quite dumb and still doesn't works fine with JSON. No matter what we do, it will iterate poorly with it. So, let's analyse the following situation:
In a test, I decided to dump the iteration. So:
{% for author in site.data.author %}
{{ author }}
----
{% endfor %}
It produces the following result:
andre{"name"=>"Andre Santos", "site"=>"test.dev";, "email"=>"andre#test.dev"} ----
john{"name"=>"John Doe", "site"=>nil, "email"=>"john.doe#test.dev"} ----
This result shows Jekyll isn't producing an array, but a Hash (notice the => symbol). So, let's try to deal with it as a Hash. If I try to print {{ author[0] it will show andre and john. Excellent! So, the next part of the Hash (the metadata) is, in fact author[1].
The final code to display the info:
{% for author in site.data.authors %}
Username: {{ author[0] }}
Full Name: {{ author[1]["name"] }}
{% if author[1]["site"] != "" %}
Site: {{ author[1]["site"] }}
{% endif %}
E-Mail: {{ author[1]["email"] }}
-----
{% endfor %}
And the result:
Username: andre
Full Name: Andre Santos
Site: http://test.dev
E-Mail: andre#test.dev
----
Username: john
Full Name: John Doe
E-Mail: john.doe#test.dev
----
Ta da!
So, to wrap it up: drop YAML and use JSON, get info from a specific part of the JSON using simple dot notation and key. When using for, deal with it as a Hash. The code becomes a little harder to deal with, but at least it's working as I wanted. In the future, if Jekyll takes JSON a little more seriously, it will probably let us iterate it a little easier.
Thank you all!

You can simplify your data file :
- user: andre
name: Andre Santos
site: http://test.dev
email: andre#test.dev
- user: john
name: John Doe
site:
email: john.doe#test.dev
Now you can get your datas like this :
<ul>
{% for author in site.data.authors %}
<li>{{ author.user }} - {{ author.name }}</li>
{% endfor %}
</ul>
Or like this :
{% assign the_user = site.data.authors | where: "user", post.username | first %}
{{ the_user.name }}

Related

Comparing two arrays, checking for matching values

Using HubL (as I'm building a module in HubSpot), I have two arrays:
topics : Which is a list of topics.
all_tags: Which is an array of all the blog tags in the system.
If I dump out these arrays, this is what it will return:
{{ topics }} prints the following: [Data, Accounting, Insight]
{{ all_tags }} prints the following: [Accounting, Press, Data]
So essentially, {{ topics }} has a tag ("Insight") that doesn't exist in the system yet.
What I'm trying to do is to create a third array, which will contain matching results from the two above arrays. For example, topics_final, once returned, should print [Data, Accounting].
But, when printing {{ topics_final }}, the array is empty.
What I've tried:
<!-- this gets all tags -->
{% set all_tags = blog_topics( blog_id , 250) %}
<!-- create arrays -->
{% set topics = [] %}
{% set topics_final = [] %}
<!-- append topic data to the array -->
{% for item in module.add_topics.topics %}
{% set topic_option = item|striptags %}
{% do topics.append( topic_option ) %}
{% endfor %}
<!-- check if topic tags exists in HubSpot -->
{% for topics in all_tags %}
{% if topics in all_tags %}
{{ topics }}
<!-- results with above
Data, Accounting, Insight
-->
{% else %}
else
{% endif %}
{% endfor %}
With the above, it just prints out the {{ topics }}, even though Insight isn't in the all_tags array.
Note: Tagging Jinja2 as the syntax is similar
A combination of the filter reject and the built in test in could help you achieve this.
Sadly, it seems the reject filter does not accept negating a test, still, you can reject all the elements of topics that are not in all_tags then reject the said elements from the topics list.
So that ends with:
{{ topics | reject('in', topics | reject('in', all_tags) | list) | list }}
Switch yields:
[
"Data",
"Accounting"
]

Liquid from AzureLogicApps parsing an object dynamically

I'm looking to parse a JSON object dynamically in a Liquid.
So far my efforts have been in vain as you can't loop over an object with a regular for loop.
The amount of properties in the ticket_attributes objects is dynamic and can vary in keynames.
Input object:
{
"action": "insert",
"state": "New",
"ticket_attributes": {
"category": "Event",
"user_name": "Customer ",
"prop3":"data1",
"prop4":"data1",
},
"ticket_number": "INC9190433"
}
Liquid snippets used that don't work:
{% for prop in content.ticket_attributes %}
{{prop[0]}}:{{prop[1]}}
{% endfor %}
{% for item in content.ticket_attributes %}
{{ forloop.index }}: {{ item.name }}
{% endfor %}
Any pointers on how to solve this inside the template?
According to some test, it seems liquid in azure logic app doesn't support loop hash. I think we can implement this requirement outside azure logic app with liquid as the template you provide in your question, but in azure logic app we can't.
For this requirement, I think we can just parse the json data, get the property ticket_attributes as string, remove the head "ticket_attributes": { and the tail }, and then insert it back to the resource json data.

Django - Access list values on template

I've to get access to all values availables in a list(array) in a Django template. All examples I find online, use dictionaries instead. So, the list is passed correctly to the template, but the following code doesn't work:
{% for item in array %}
field_names = field_names + "{{ item }},";
{% if forloop.last %}
field_names = field_names + "{{ item }}";
{% endif %}
{% endfor %}
I could access the values using {{ field.[0] }} , {{ field.[1] }} , etc. But, I have to make it work independently of the list's size.
Can anybody give me a hint?
P.S. - I cannot use a dictionary to pass the values to the template, since that code wasn't donne by me, and I'm not supposed to touch it.
In your view:
my_joined_list = ",".join(somelist)
In your template:
field_names = {{ my_joined_list }}
Resolved it!! I just passed the variable to the template exactly as i needed it and used {{ array|safe }} to resolve it to a Javascript variable. Done!

Django template - compare date to today

I'm trying to make a simple IF function that checks if the date of an item is equal to today or not. Unfortunately I can't get it to work. I basically decides that the statement is false and doesn't show any content, even when it show. I am not getting any error either.
The code I use is following:
{% if item.valid_until.date == now.date %}
<div id="what_i_want_to_show">
CONTENT
</div>
{% endif %}
The content of valid_until is a DateTimeProperty from a Google App Engine app. Normally working with this in Django template doesn't cause any problems. Solutions from similar questions on SO didn't work so far. Am I missing something obvious?
UPDATE 1:
This statement runs in a loop on the result of a database query. Therefore doing the comparison in the view didn't work as far as I could see, since I would have to send the variable with each item.
There are 2 aproach on this case:
1st:
you can add a #property on model
Model:
from datetime import date
#property
def is_past_due(self):
return timezone.now() > self.valid_until # if valid until default is timezone.now else change it
Template:
{% if item.is_past_due %}
<!--In the past-->
{% else %}
{{ item.valid_until.date|date:"Y-m-d" }}
{% endif %}
2nd:
declare a today date with format on template
{% now "Y-m-d" as todays_date %}
{% if todays_date < item.valid_until.date|date:"Y-m-d" %}
<div id="what_i_want_to_show">
CONTENT
</div>
{% endif %}

Guestbook application

I made a very minor mod to the GqlQuery to retrieve only specified records using the
'where' keyword. The output, however, displays all entries from the guestbook db!
(I need to filter the data by author)
Guestbook5_datastore code:
#greetings = db.GqlQuery("SELECT * FROM Greeting ORDER BY date DESC LIMIT 10")
greetings = db.GqlQuery("SELECT * FROM Greeting where greeting.author='mike'")
index.html code:
{% for greeting in greetings %}
{% if greeting.author %}
<b>{{ greeting.author.nickname }}</b> wrote:
{% else %}
An Anonymous person wrote:
{% endif %}
<blockquote>{{ greeting.content|escape }}</blockquote>
{% endfor %}
Your author property is not a string, so I don't think you can do
greeting.author='mike'
I'm surprised that you wouldn't get an error telling you that though, rather than it returning them all!
You're attempting to filter based on a property of another entity, which would require a join. This isn't supported in App Engine.

Resources