Closed tgoorden closed 6 years ago
Hi, @tgoorden! Thank you for using Jekyll-Pug.
The solution to this problem is to also indent the for-loop like so:
ul.navbar-nav.ml-auto
| {% for page in site.pages %} {% if page.title %}
li.nav-item
a.nav-link(href='{{ page.url | prepend: site.baseurl }}') {{ page.title }}
| {% endif %} {% endfor %}
OK, it does work with this very specific indentation. Could you explain why though? It sees counter-intuitive, no?
It's important to understand how Pug works.
Unlike HTML, ending tags are not needed. When you indent a line of code, it wraps it with the parent.
So, look at this example:
div
p Welcome
In this case, the pug output would simply be:
<div>
<p>Welcome</p>
</div>
Now, let's take a look at your code example and why it does not work.
ul.navbar-nav.ml-auto
| {% for page in site.pages %}{% if page.title %}
li.nav-item
a.nav-link(href='{{ page.url | prepend: site.baseurl }}') {{ page.title }}
| {% endif %}{% endfor %}
The first thing pug will see is your ul
element. It sees that there are no child elements (Indented lines of code) directly under it, so it will render this:
<ul class="navbar-nav ml-auto">
</ul>
The next thing it looks at is the plain-text for the start of your jekyll for-loop.
The error arises when you try to indent the li
element and put it inside the for loop.
Going back to what was said earlier, Pug needs to generate an ending tag when generating HTML to wrap the child items.
The question now is how do you create an ending tag for | {% for page in site.pages %} {% if page.title %}
?
You can't, so it errors out.
Let me know if that makes sense to you.
In conclusion, you can't provide any children to plain-text in Pug. You can only indent true elements.
It's quite interesting behaviour. Going by what you said, I tried out the following:
ul
| {%for page in site.pages %}
p {{ page.title }}
| {% endfor %}
Which compiles just fine! It seems the compiler is doing the following:
ul
, it increments the indentation level.ul
. However, the loop is not broken!This implies you can write really weird, but correct code like this:
.example
ul
| {%for page in site.pages %}
| {% if page.title %}
p {{ page.title }}
| {% endif %}
| {% endfor %}
This compiles as well! However... Try using that block of code as {{ content }}
in a layout. It actually "breaks out" of the containing divs
, decreasing the indentation level at which the p
tags are dropped in the resulting page.
In short, it seems that the way this currently works has severe issues. It seems that inner code shouldn't be able to affect its "surrounding" tags, but it totally can. And, obviously, the readability of the code is terribly confusing.
To add some constructive ideas: Meteor solved the combination of Jade + Spacebars (their templating engine) a bit more elegantly, essentially with custom tags. You would end up writing code like this:
ul
for page in page.sites
li {{ page.title }}
No ending endfor
needed. Wouldn't that work here as well?
I don't think there is any problem here. It makes complete sense when you understand how Pug works. Keep in mind, I didn't code the functionality of for loops.The piped for-loops are a part of Liquid's template engine - What Jekyll uses with HTML. All this plugin does is allow you to code in familiar Pug code and be able to access all of Jekyll's features and variables.
Maybe, in the future, I'll completely replace the Liquid Template Engine for Pug, but that could possibly sacrifice the ability for users to add plugins that use custom template tags and such.
For now, Jekyll-Pug works wonderfully and I find it a dream to code in.
OK, so I can't figure out how to make this work:
If the
li
tag has an indent before it, the code won't compile. However if you don't indent it, it will not be placed within theul
tag.