The for "loop" and inline "if" Syntax
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
Let's give ourselves a challenge! Our products are printing out a bit weird
right now because they're floating but not breaking correctly. To fix this,
we need to wrap every three products in their very own row
div.
To do this, we can use a divisible by() test to see if the item number we're on is divisible by three:
<div class="row">
{% for product in products %}
<div class="span4">
{# ... #}
</div>
{% if loopNumber is divisible by(3) %}
</div><div class="row">
{% endif %}
{% endfor %}
</div>
Just like functions and filters, sometimes a "test" also takes one or more arguments.
When we refresh, Twig is sad because the loopNumber
variable is undefined.
Yep, that's totally my fault, I made up that variable out of thin air. So
how can we figure out how many items into the loop we are?
The Magical loop Variable
Twig comes to the rescue here and lets us say loop.index
.
{% for product in products %}
{# ... #}
{% if loop.index is divisible by(3) %}
</div><div class="row">
{% endif %}
{% endfor %}
When we refresh, things work awesomely! So where did this magical loop variable come from? Normally in Twig, we have access to a few variables that were passed to us and that's it. If we use an undefined variable, we see an error.
This is all 100% true. But when we're inside a for tag, we magically have
access to a new variable called loop. loop.first
and loop.last
tell us if this is the first or last item in the collection while loop.index
counts up 1, 2, 3, 4 and so on for each item. Twig has a lot of really slick
features like this, which you can find out by reading further into its docs.
In fact, to avoid an extra row being added if we have exactly 3, 6 or 9 objects,
let's not print a new row
if we're on the last item:
{% for product in products %}
{# ... #}
{% if loop.index is divisible by(3) and not loop.last %}
</div><div class="row">
{% endif %}
{% endfor %}
And not that it matters for Twig, but let's also move our "even" products message into its own row where it belongs.
{# templates/homepage.twig #}
{# ... after the for loop #}
{% if products|length is even %}
<div class="row">
<div class="span12">
There is an even number of products! OMG!
</div>
</div>
{% endif %}
When we refresh, everything looks good and clean!
The for-else tag
While we're talking about cool for
loop features, let's see another one:
the for-else
trick. Instead of seeing if products
is empty, we can
add an else
tag inside of the for
loop.
{% for product in products %}
{# ... #}
{% else %}
<div class="alert alert-error span12">
It looks like we're out of really awesome-looking penguin clothes :/.
</div>
{% endfor %}
If products
is empty, it skips the for
loop and calls the else
section instead. When we try it, it still works great.
The inline if Syntax
Finally, let's see a really short syntax you can choose to use instead of
the classic if
tag. Head back to the banner template where we're setting
the backgroundColor
variable if it's not set and then printing it. Let's
remove all of this and instead put all the logic in the "say something" block:
<div class="well" style="background-color: {{ backgroundColor is defined ? backgroundColor : 'lightBlue' }};">
{# ... #}
</div>
You may be familiar with this syntax from another language, but if you're
not, don't worry! It looks odd, but is really easy. The first part is a condition
that returns true or false, just like an if statement. If it's true, the first
variable backgroundColor
is printed. If it's false, the second string
lightblue
is printed. The result is identical to before.
We could also to use <a href="http://twig.sensiolabs.org/doc/filters/default.html">default</a> filter instead of
is defined
test, for example:This is more readable and elegant solution, imo.