3

I have a Matrix field with some different block types; images, videos, text, etc. When I loop over the blocks I have some extra code (facebook and twitter sharing, back-button, etc) that should only be output for the last "text" block.

How can I know, inside the loop, if the current block is the last of its type?

  • Did you try my approach, aelvan? I had issues with the type filter, but 2.2 fixed this for me. – carlcs Sep 3 '14 at 10:22
  • Yes, I tried it, and it works. But I don't think it's a much better solution than mine. :) The increment of the loopIndexText variable inside the include actually makes it a bit more obscure to me. Also, if you needed to use the with { ... } only functionality of the include method, I don't think this would work? What I was hoping was that there was some kind of block.lastOfType property that wasn't documented. :) – André Elvan Sep 3 '14 at 11:05
  • And regarding performance, both methods add one query extra. – André Elvan Sep 3 '14 at 11:05
  • Yes you're right, it's not that much better. But now that the type filter works for me I tried a new idea. Your mentioning of block.lastOfType guided me in the right direction. ;) See new answer below! – carlcs Sep 3 '14 at 11:45
5

What about comparing the currently looped block ID with the ID of the last block of type "text"?

_entry.html:

{% set lastTextBlock = entry.simpleMatrix.type('text').last() %}
{% set lastTextBlockId = lastTextBlock ? lastTextBlock.id : null %}

{% for block in entry.contentBlocks %}
    {% include '_blocks/' ~ block.type|lower %}
{% endfor %}

_blocks/text.html:

{% if block.id == lastTextBlockId %}
    ...
{% endif %}
| improve this answer | |
  • That is quite clever! It's the cleanest solution by far. For some reason it adds an extra query, but the impact on performance is probably negligible. I'm opting for clean code. :) – André Elvan Sep 3 '14 at 12:24
  • @aelvan for better performance you could save that last "text" block's ID in a var before looping though your blocks. I'll update the answer, even if it makes the code look a little less clean :) – carlcs Sep 3 '14 at 12:33
  • I still have one issue with the approach (maybe this also applies to the other approaches?). It doesn't update with Live Preview from the CP, this probably has s.th. to do with caching? – carlcs Sep 3 '14 at 12:35
2

What about using the length filter on a type filtered array of block models to get the total number of your "text" blocks. And then combine that with a counter in your block include to conditionally output the buttons?

_entry.html:

{% set lastTextBlock = entry.contentBlocks.type('text')|length %}
{% set loopIndexText = 0 %}

{% for block in entry.contentBlocks %}
    {% include '_blocks/' ~ block.type|lower %}
{% endfor %}

_blocks/text.html:

{% set loopIndexText = loopIndexText + 1 %}

{% if loopIndexText == lastTextBlock %}
    ...
{% endif %}
| improve this answer | |
1

I've come up with this very "manual" approach, which works ok:

{% set lastTextBlock = -1 %}
{% for block in entry.contentBlocks %}
    {% if block.type=='text' %}
        {% set lastTextBlock = loop.index0 %}
    {% endif %}
{% endfor %}

{% for block in entry.contentBlocks %}
    {% include '_blocks/' ~ (block.type | lower) with { 'addButtons': loop.index0==lastTextBlock } %}
{% endfor %}

But is there a better way? It feels a bit dirty and inefficient to loop over the blocks two times.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.