Iterate over global data subfolder in Eleventy / 11ty - json

I'm using Eleventy and have created the subfolder yummy in my global data folder, that contains the following files:
\src\_data\yummy\drinks.json
\src\_data\yummy\food.json
When I use {{ yummy | dump }} I get the following output:
{"drinks":[{"name":"Milk","price":5},{"name":"Water","price":1}],"food":[{"name":"Pizza","price":4},{"name":"Hot dog","price":2},{"name":"Sallad","price":1},{"name":"Avocado","price":3}]}
I want to create a list with all entries in both json-files. I almost have achieved this with the following loop:
<ul>
{% for key, val in yummy %}
<li>{{ val[0].name }} cost {{ val[0].price }}$</li>
{% endfor %}
</ul>
However, since I'm using [0], the output is only the first entry in each json-file:
- Milk cost 5$
- Pizza cost 4$
I want all entries and have tried the following, but get no output at all:
<ul>
{% for key, val in yummy %}
<li>{{ val[key].name }} cost {{ val[key].price }}$</li>
{% endfor %}
</ul>

Managed to solve this myself by adding a second loop.
<ul>
{% for key, val in yummy %}
{% for entry in val %}
<li>{{ entry.name }} cost {{ entry.price }}$</li>
{% endfor %}
{% endfor %}
</ul>
Outputs as:
- Milk cost 5$
- Water cost 1$
- Pizza cost 4$
- Hot dog cost 2$
- Sallad cost 1$
- Avocado cost 3$

Related

Loop unique values in nested data tree in Jekyll

I have a data files with different items. Each item have nested tasks. I am trying to loop the nested tasks and present each task by the task type.
YML DATA
- name: Outside
description: Description
tasks:
- type: Food
name: Eat it outside
status: working
- type: Drinks
name: Drink it outside
status: working
- name: Inside
description: Description
tasks:
- type: Food
name: Eat it inside
status: pending
- type: Drinks
name: Drink it inside
status: working
Liquid
{% for item in site.data.info %}
{% assign grouped-tasks-by-type = item.tasks | group_by: "type" %}
{% for task in grouped-tasks-by-type %}
<h2 class="task-type">{{ task.type }}</h2>
<ul>
{% for task in item.tasks %}
{% if task.status == 'working' %}
<li>{{ item.name }}: {{ task.name }}</li>
{% endif %}
{% endfor %}
</ul>
{% endfor %}
{% endfor %}
Expected result (HTML)
<h2 class="task-type">Food</h2>
<ul>
<li>Outside: Eat it outside<li>
</ul>
<h2 class="task-type">Drinks</h2>
<ul>
<li>Outside: Drink it outside<li>
<li>Inside: Drink it inside<li>
</ul>
However, I am getting a full blank result. Is this possible to do with group_by?
I hope my algorithm below serves you well. I was able to achieve your expect end result with the algorithm. I was unable to utilize the group_by in my solution. The sample code contains Liquid comment blocks to explain my thought process.
Testing
I used the minima git repo, with command jekyll s. I placed your YML data in a file with path _data/info.yml in my locally cloned minima git repo. I used post.html as the code sandbox.
You can print out the Liquid variables to the DOM by doing {{ all_food_types | json }} in the code.
Solution
{%- comment -%}
End Goal: Find all the food types for <h2>.
1. Use map: "tasks" to gather all the tasks into a single array.
This will cause the loss of Outside/Inside information for each task
2. Use map: "type" to create a list of food types ("Food", "Drinks")
3. Use uniq to remove duplicate food types from the array
{%- endcomment -%}
{% assign all_food_types = site.data.info | map: "tasks" | map: "type" | uniq %}
{%- comment -%}
End Goal: Loop through all the data looking
for a specific food type (Food, Drinks)
and group them together
{%- endcomment -%}
{% for food_type in all_food_types %}
<h2 class="task-type">{{ food_type }}</h2>
<ul>
{% for item in site.data.info %}
{% for task in item.tasks %}
{% if task.status == 'working' and task.type == food_type %}
<li>{{ item.name }}: {{ task.name }}</li>
{% endif %}
{% endfor %}
{% endfor %}
</ul>
{% endfor %}
An aside, for whatever reason, my liquid ends up using a lot of arrays and for-loops.

List items from a collection by front matter array values

I have a Jekyll site with a collection, colleges, that I want to sort and display by a custom rankings front matter attribute. Here is an example of items in the collection:
---
title: Example College
score: 88
rankings:
- top accredited colleges
- most affordable
---
...
---
title: Sample College
score: 75
rankings:
- most affordable
- best online programs
---
...
---
title: Example University
score: 75
rankings:
- top accredited colleges
- best online programs
---
I would like to display the different rankings as headings with the colleges listed under them like so:
top accredited colleges
- Example College
- Example University
most affordable
- Example College
- Sample College
best online programs
- Sample College
- Example University
I've tried using Liquid's group_by filter like so:
{% assign groups = site.colleges | group_by: "rankings" %}
{% for group in groups %}
<h2>{{ group.name }}</h2>
<ul>
{% for college in group.items %}
<li>{{ college.title }}</li>
{% endfor %}
</ul>
{% endfor %}
But this seems to group the rankings front matter by an exact match of the full array rather than separating out the different values it contains:
<h2>[top accredited colleges, most affordable]</h2>
<ul>
<li>Example College</li>
</ul>
<h2>[most affordable, best online programs]</h2>
<ul>
<li>Sample College</li>
</ul>
<!-- etc -->
How do I separate out the individual values from the rankings front matter array in the output?
This can do the trick :
{% assign allRankings = site.colleges | map: "rankings" %}
{% assign rankingArray = "" | split:"" %}
{% for rankings in allRankings %}
{% assign rankingArray = rankingArray | concat: rankings | uniq %}
{% endfor %}
{% for ranking in rankingArray %}
<h2>{{ ranking | capitalize }}</h2>
<ul>
{% for college in site.colleges %}
{% if college.rankings contains ranking %}
<li>{{ college.title }}</li>
{% endif %}
{% endfor %}
</ul>
{% endfor %}

Loop through posts and filter all cities where state is specified

Given a number of markdown files within an offices folder, I need to loop through each one and find/render the city value where the state is a given value. So far I have this, but it renders every city regardless of the where clause:
<ul class="cities">
{% for post in site.offices | where: "state", "florida" %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
<li>{{ post.title }}</li should list all of the cities from the markdown files that have Florida as their state.
This is a sample markdown file:
---
office_id: 5
title: Orlando
state: florida
phone: 123-456-7890
---
I discovered that I had to set an assignment first:
{% assign cities = (site.offices | where: "state" , "florida") %}
{% for city in cities %}
<li>{{ city.title }}</li>
{% endfor %}

In Jekyll, how can I use subcategories of a variable in the layout of another collection?

I have a collections of projects. Part of each project is a list of people who have worked on that project:
---
layout: project
name: Important Project
participants:
- name: julia
role: owner
- name: paul
role: manager
- name: chris
role: implementer
---
Each of these people are in a collection themselves and have a page where their details are listed. I'd like to include the projects they've been working on and what their role was. This is my best effort but doesn't work:
{% for project in site.projects %}
{% if project.participants['name'] == {{ page.name }} %}
<p>{{ project.name }} - {{ project.participants['role'] }}</p>
{% endif %}
{% endfor %}
Any suggestions are most welcome.
Assuming this structure:
# _config.yml
collections:
- people
- projects
Then directory structure like:
_projects/project1.md
_people/person1.md
_people/person2.md
With person1.md front-matter like:
---
name: julia
---
And the above front-matter you provided, this is how to display the list of projects and roles of each person:
{% for person in site.people %}
Person {{person.name}}
{% for project in site.projects%}
{% assign person_project = project.participants | where:"name",person.name | first %}
Project: {{project.name}}
Role: {{person_project.role}}
{% endfor %}
{% endfor %}
Then the output looks like:
Person julia
Project: Important Project
Role: owner
Then you can improve the output as you wish, for example with a table:
{% for person in site.people %}
<table>
<caption>{{person.name}} projects</caption>
<tr>
<th>Project</th>
<th>Role</th>
</tr>
{% for project in site.projects%}
{% assign person_project = project.participants | where:"name",person.name | first %}
<tr>
<td>{{project.name}}</td>
<td>{{person_project.role}}</td>
</tr>
{% endfor %}
</table>
{% endfor %}
output:
julia projects
Project Role
Important Project owner
I imagine that your participants items look like this :
---
short: julia
firstname: Julia
lastname: Last
layout: participant
---
Content
In your participant layout you can do :
<h2>Participant : {{ page.firstname }} {{ page.lastname }}</h2>
{{ content }}
<h2>Projects :</h2>
<ul>
{% for project in site.projects %}
{% for participant in project.participants %}
{% if participant.name == page.short %}
<li>{{ participant.role }} in {{ project.name }}</li>
{% endif %}
{% endfor %}
{% endfor %}
</ul>
In participant

How to group a collection in Liquid?

I have a Jekyll app (using Liquid) and I'd like to know how to, in Liquid, group a collection of items into a small subset of collections.
For instance, pretend I have this array:
fruits = ['apples', 'oranges', 'bananas', 'pears', 'grapes']
What I'd really like to do, in the Liquid page, is get this:
fruit_groups = [['apples', 'oranges'], ['bananas', 'pears'], ['grapes', null]]
For example, Ruby on Rails can do this with their .group_by method attached to enumerables.
Can I do this in Liquid?
Use case: I have a big collection of items, but I need to convert them into columns of <ul> elements. So, if I have three columns, I need to get three sub-collections.
Thanks!
This doesn't answer your question directly, but I'm not sure that you'd want to do what you're describing (and I'm pretty sure you can't) - Liquid is a templating system, not a fully fledged programming language. I suspect that you'll be able to achieve your end goal using some of the for loop and cycle features: http://code.google.com/p/liquid-markup/wiki/UsingLiquidTemplates
eg:
<ul>
{% for fruit in fruits %}
{% capture pattern %}{% cycle 'odd_class', 'even_class' %}{% endcapture %}
<li class={{ pattern }}>{{ fruit }}</li>
{% endfor %}
</ul>
or
<ul class="odd">
{% for fruit in fruits %}
{% capture pattern %}{% cycle 'odd', 'even' %}{% endcapture %}
{% if pattern == 'odd' %}
<li>{{ fruit }}</li>
{% endif%}
{% endfor %}
</ul>
<ul class="even">
{% for item in fruits %}
{% capture pattern %}{% cycle 'odd', 'even' %}{% endcapture %}
{% if pattern == 'even' %}
<li>{{ fruit }}</li>
{% endif%}
{% endfor %}
</ul>
If you have three columns, you'd just have three steps in your cycle, and three directions to go in your if statement.
If all that fails, you could write a plugin (in Ruby) that will restructure your data before it ever hits the template layer, but I suspect that would be overkill.