List data concatenated in output

Hi Everyone,
This is my first post. I’ve got a nubie issue that I hope offers a little bit of challenge (I tend to “get” the complex stuff but miss the simple stuff sometimes). Basically, I’m calling list items from a .yml data file but the output is concatenating the list. My code appears below. If anyone can show me what I’m missing I’d REALLY appreciate it. - Thanks in advance!

YML:

modules:
- number: "01"
  start: May 31
  name: Introduction
  description: This is a description
  image: "/images/conduct.jpg"
  objectives:
    - "Explain the importance of services to a country’s economy."
    - "Demonstrate how services are defined using the concept of non-ownership."
    - "Classify a company as one of four common types of business services."
  topics:
    - "Topic #1"
    - "Topic #2"
    - "Topic #3"

For Loop:

<ul>
       {% for module in site.data.bmgt205.modules %}
              {% if module.number == "01" %}
                    <li>{{ module.objectives }}</li>  
               {% endif %}
       {% endfor %}      		    
</ul>

Results:
“Explain the importance of services to a country’s economy.Demonstrate how services are defined using the concept of non-ownership.Classify a company as one of four common types of business services.”

What I’m trying to get is:
list:
• item 1
• item 2
• etc.

you probably just need another for loop for item in module.objectives?

1 Like

You are almost there! I think a good solution is to use another for loop in your code. I took your data file and played around with it a bit, so I did reformat the structure, mostly because it is how I work with YAML files, so feel free to re-format as you see fit.

In future posts, please use proper code blocks as your code was not easy to read/copy/paste since it came through formatted as HTML.

I modified your dataset to look like this:

items:
  - number: "01"
    start: May 31
    name: Introduction
    description: This is a description
    image: "/images/conduct.jpg"
    objectives:
      - "Explain the importance of services to a country’s economy."
      - "Demonstrate how services are defined using the concept of non-ownership."
      - "Classify a company as one of four common types of business services."
    topics:
      - "Topic #1"
      - "Topic #2"
      - "Topic #3"
  - number: "02"
    start: June 04
    name: After introduction
    description: This is a second description
    image: "/images/conduct2.jpg"
    objectives:
      - "Second objective, line 1"
      - "Second objective, line 2"
      - "Second objective, line 3"
    topics:
      - "Second Topic #1"
      - "Second Topic #2"
      - "Second Topic #3"

Then I created two for loops to address the formatting you want:

    {%- assign modules = site.data.modules.items | where: "number", 01 -%}
    {%- for module in modules -%}
        <p>Module: {{ module.number }}</p>
        {%- if module.objectives -%}
            <ul>
                {%- for objective in module.objectives -%}
                    <li>{{- objective -}}</li>
                {%- endfor -%}
            </ul>
        {%- endif -%}
    {%- endfor -%}

By using assign, you can read the dataset and add a Liquid where clause, allowing you to get rid of that extra if statement you have in the original code. If you were to remove the where clause in the assign declaration, all the modules and objectives will display.

The first for loop displays the module number or any other details you want (start, name, etc.).

While probably not 100% necessary, I added an if statement to make sure objectives exist in the data. If you remove that if statement and there are no objectives, then there will be a dangling <ul></ul> block in the final HTML source code.

The starting <ul> tag starts an unordered list. The second for loop displays all the objectives as list items by using an <li></li> block. After the for loop, the objectives are closed out with an ending </ul> tag.

Please note I had a super hard time with that where clause in the past. Code samples say you can type the code like this:

where: "number", "01"

But that code won’t work. You need to remove the quotes for the module number, like this:

where: "number", 01

I’m sure it is my lack of YAML knowledge that is to blame, but do pay extra close attention to that when it comes to a number. Of course where: "start", "May 31" works just fine, so go figure :slight_smile:.

You might want to consider using collections instead of data. The reason collections are useful is each module will be a markdown or HTML file. That is useful because when you edit them in standard markdown using a browser and you will get spelling and grammar checks. You can also add whatever tailored content that may not come with using hard-coded data. Just a thought and certainly not a requirement.

Finally, I created a series of videos that demonstrate how to work with data in Jekyll. It seems like you have most of it down, so you can use them as a reference if you like. The third video (using custom data) is most pertinent to the topic of this post. Here are all three:

1 Like

Yes Jekyll will represent an array as a string and an inner for loop is the way to go.

So you have ul and li and within the li you have another section of ul and li

For interest, without using for loop.

Inspect your array as an array of strings.

{{ module.objectives | jsonify }}

Or use inspect if you want a Ruby object representation.

Or even for your entire data file.

```json
{{ site.data.abc | json }}
```

You could also use join filter if you wanted to join your elements with a comma for example instead of making an inner list.

See methods talked about above on this Cheatsheet.

@BillRaymond hmm sorry about the quoting issue. I’m confused too.

Quoting as “01” makes sense as it forces a string. Similarly True in YAML will become a boolean type unless you quote as "True" to get a string.

And using where I would expect to need quotes too. To avoid referencing a variable, you would use quotes for a string. Don’t know what’s up with the number.

Hi Bill,

Wow, that is a great explanation. I wasn’t expecting so much detail but it really helps. Thank you so much! I will also try to use code blocks in the future. I didn’t see how to do that when I was writing the post but I’ll make a point of looking for how to do it.
Thanks again!

  • Scott

Thanks for the Cheatsheet link Michael. That will be very helpful going forward.
Just so you know, I’m drawing data to several different pages from one data file. Nested lists were giving me different results in each context, so I started converting the values to string. It’s probably not a smart move but helped pin down the number of assumptions I had to deal with.
As for the number, the module names in my data file match the folders in my collection, so that when the navigation menu is generated, it contains the correct links. It’s probably easier to use separate data files but I was trying to do everything from one file.
Thanks again for your help!

1 Like

@MichaelCurrin yes, it was very weird! Part of me wonders if it has to do with being a top-level data element in the YAML (dash - in front), but I regularly give up researching it further after I get it working :slight_smile:

1 Like

@sbootes no problem! Hope one of those solutions works for you.

@sbootes

With Jekyll you can store data in a YAML file or in the frontmatter portion of a page (whether a post or standard page or a collection page)

So instead of one data file or multiple data files, you could store data in your collection. No lookup needed. No nested for loop.

Try this. Assuming your collection is called modules and is configured in your confif to output as a file for each item.

_modules/01-intro.md

---
title: Introduction
number: "01"
start: May 31
name: Introduction
description: This is a description
image: "/images/conduct.jpg"
objectives:
  - "Explain the importance of services to a country’s economy."
  - "Demonstrate how services are defined using the concept of non-ownership."
  - "Classify a company as one of four common types of business services."
topics:
  - "Topic #1"
  - "Topic #2"
  - "Topic #3"
---

You don’t need anything in the body of the page.

Then in your config you could set layout as module.html for the whole collection.

Then you could have _layout/module.html as:

---
layout: default.html
---
<h1>Module: {{ page.number }}</h1>

{%- if page.objectives -%}
<h2>Objectives</h2>

<ul>
    {%- for objective in page.objectives -%}
         <li>{{ objective }}</li>
    {%- endfor -%}
  </ul>
{%- endif -%}