I have some JSON that looks like this (longer with more sections, but this is the jist of the structure):
{
"navTree": [
{
"lvl1Item": "Graphic Design",
"lvl1Link": "/graphic-design",
"hasLvl2Items": true,
"lvl2Items": [
{
"lvl2Item": "Logos",
"lvl2Link": "/logos"
},
{
"lvl2Item": "Digital Graphics",
"lvl2Link": "/digital"
}
]
},
{
"lvl1Item": "Illustration",
"lvl1Link": "/illust",
"hasLvl2Items": false,
"lvl2Items": null
},
{
"lvl1Item": "Character Design",
"lvl1Link": "/characters",
"hasLvl2Items": false,
"lvl2Items": null
}
]
}
I went for a JSON like that cause I figured it'd make things easier if I rearranged sections of my portfolio website I'm trying to build.
I'm trying to use it to render a plaintext-HTML navigation menu that'd ultimately look like this, after build and output by 11ty (Eleventy):
<ul>
<li><a href="/graphic-design" class="sidenav-lvl1">Graphic Design</a></li>
<ul>
<li><a href="/graphic-design/logos" class="sidenav-lvl2">Logos</a></li>
<li><a href="/graphic-design/digital" class="sidenav-lvl2">Digital Graphics</a></li>
</ul>
<li><a href="/illust" class="sidenav-lvl1">Illustration</a></li>
<li><a href="/characters" class="sidenav-lvl1">Character Design</a></li>
</ul>
But for going from JSON→HTML, this is the best I could come up with using Nunjucks…
<ul>
{% for lvl1Item in navTree %}
<li>
<a href="{{ lvl1Item.lvl1Link }}" class="sidenav-lvl1">{{ lvl1Item.lvl1Label }}</a>
<ul>
{% if lvl1Item.hasLvl2Items %}
<li>Lvl 2 True!</li> {# Just testing to see if it found anything. #}
{% for lvl2Items in lvl1Item %}
<li>
<a href="{{ lvl1Item.lvl1Link }}/{{ lvl1Item.lvl2Items.lvl2Link }}" class="sidenav-lvl2">{{ lvl1Item.lvl2Items.lvl2Label }}</a>
</li>
{% endfor %}
{% endif %}
</ul>
</li>
{% endfor %}
</ul>
…because I made a lot of clumsy attempts to access object grandchildren/subchildren to no results. I'm not fluent in Nunjucks, and I'm only recently learning more javascript, so I'm starting to wonder if it's possible to interact with object grandchildren in the way that I'm trying to.
Anyway, here's the HTML result, the 11ty output:
<ul>
<li>
<a href="/graphic-design" class="sidenav-lvl1">Graphic Design</a>
<ul>
<li>Lvl 2 True!</li>
</ul>
</li>
<li>
<a href="/illust" class="sidenav-lvl1">Illustration</a>
<ul></ul>
</li>
<li>
<a href="/characters" class="sidenav-lvl1">Character Design</a>
<ul></ul>
</li>
</ul>
I don't mind the empty <ul>
s for non-existent subchildren unless they're an accessibility problem(?). I'm able to make code that detects the existence of subchildren by me reporting it through the true/false hasLvl2Items
in the JSON (my little Lvl 2 True!
firing off), but how do I make something that starts outputting the submenu items? Or a better Nunjucks/JSON setup for my malleable site nav menu altogether?
This is the offending line:
{% for lvl2Items in lvl1Item %}
Since lvl1Item
is the "current" element of your loop, it has data-members, such as lvl1Item
, lvl1Link
, hasLvl2Items
and most importantly lvl2Items
. So you need to iterate lvl1Item.lvl2Items
with an iterator, say lvl2Item
(singular), as:
{% for lvl2Item in lvl1Item.lvl2Items %}
and of course adjust the inner content of the loop:
{% for lvl2Item in lvl1Item.lvl2Items %}
<li>
<a href="{{ lvl1Item.lvl1Link }}/{{ lvl2Item.lvl2Link }}" class="sidenav-lvl2">{{ lvl2Item.lvl2Label }}</a>
</li>
{% endfor %}
Secondly, notice that you only have lvl2Items
if hasLvl2Items
is true. So you need to check whether lvl1Item.hasLvl2Items
is true and only have the loop above if so.