22

I need to take control over the rendering of a field_admin_tags field in a node.html.twig template.

This WORKS:

  • {{ content.field_admin_tags }} — Renders everything (label + all field values)
  • {{ content.field_admin_tags.0 }} — Renders only the first value in the field, and no label

PROBLEM: I have no control over the markup surrounding the tags, e.g. <ul><li>...</li></ul>.

So my idea was to iterate over the render array.

But that DOES NOT work:

{% for tag in content.field_admin_tags %}
  {{ tag }}
{% endfor %}

I get: Exception: Object of type Drupal\node\Entity\Node cannot be printed.

I think I'm iterating over the keys/values of the render array vs the items inside the field (if I print out an "X" in each loop, I get 20 X's while I only have two or three values in this field).

I'd like to iterate over content.field_admin_tags.0, content.field_admin_tags.1, etc.

Any idea how to fix this? Thanks.

14

You can fix this in a field twig. There you can use the existing loop to iterate over the field items:

node.html.twig

{{ content.field_admin_tags }}

field--field-admin-tags.html.twig

<ul{{ attributes }}>
  {% for item in items %}
    <li>{{ item.content }}</li>
  {% endfor %}
</ul>

This example replaces <div> with <ul>. Don't remove {{ attributes }} or bypass the field template, see What can break quickedit, and how do I fix it?

  • This is called from the parent template with {{ content.field_admin_tags }} – aydow Nov 12 '18 at 23:32
22

Agree with 4k4 the field template is the best place, if you really want it in the entity template (e.g. node) you can do something like this:

{% for key, item in content.field_tags if key|first != '#' %}
  <div class="item-{{ key + 1 }}">{{ item }}</div>
{% endfor %}

But honestly I think it's a bit ugly, the field template is the right place.

  • 1
    Agreed, it's a bit ugly. ;) Thanks for the code snippet, though. – AngularChef Jul 29 '16 at 8:42
  • Works perfectly with different types of entites – Christophe CARON May 14 at 14:59
11

If you, like me, are looking for a way to iterate through paragraphs on a node's twig template, here is how to do it:

Suppose you have a node with a multivalued paragraph field, so a content editor can create multiple paragraphs and you wish to iterate through each paragraph on the nodes twig template (for example to add a wrapper around each paragraph):

{% for key,value in node.my_paragraph_field.value %}
    {{ content.my_paragraph_field[key] }}
{% endfor %}

UPDATE: I needed to find another way to print all paragraphs without using content. The content variable contains everything you set up in the 'Manage display' section of the node, but my current work method is to never use 'Manage display' nor layouts since you can actually access all data in the node twig file, and almost all settings you would do on 'Manage display', like applying an image style, or setting a date format, ... you can do directly in twig.

For me this is an advantage because I know that everything I see comes from the twig file, and I do not need to look for some obscure field settings that may add classes somewhere. So everything I see comes from just one place (the nodes twig file) and not a combination of the twig file and the manage display screen.

Anyway, using the awesome Twig Tweak module, here is how to print a multi value paragraph field in a node's twig file without having to use the content variable:

{% for item in node.field_paragraphs %}
    {{ drupal_entity('paragraph', item.target_id) }}
{% endfor %}
1

I have found the #items property to be useful when building loops of unknown length in Twig:

print number of values within field:
{{ content.field_admin_tags['#items']|length }}

---

{# remember length in variable (minus 1 because it starts from 0): #}
{% set numTagsIndex = content.field_admin_tags['#items']|length - 1 %}

{# loop until the max value is reached: #}
{% for i in 0..numTagsIndex %}
  {{ content.field_admin_tags[i] }}
{% endfor %}
0

If you want to place additional wrappers around the fields inside the paragraph field or need for some reason a particular paragraph reference field value, you can do the following:

{% for key,value in node.paragraph_field_name.value %}

<div class="example-wrapper">
{{ content.paragraph_field_name[key]['#paragraph'].field_content.value }}
</div>

{% endfor %}

By doing {{kint(content.paragraph_field_name[key])}}, you'll see that the fields are accessible inside the ['#paragraph'] part of the array.

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.