Use "is sequence" Twig test to prevent fatal errors when looping on slots

Created on 30 October 2024, 4 months ago

Problem/Motivation

If you use Grid Row component in a view and you have only one result, you will get this fatal error:

Exception: Object of type Drupal\node\Entity\Node cannot be printed. in Drupal\Core\Template\TwigExtension->escapeFilter()

Because content is a single renderable, so we are looping on the renderable properties:

  {% for item in content %}
    {% set col_sizes = [card, card_lg, mobile, mobile_lg, tablet, tablet_lg, desktop, desktop_lg, widescreen] %}
    <div{{ create_attribute({'class': col_sizes}) }}>
      {{ item }}
    </div>
  {% endfor %}

Proposed resolution

Since Twig 3.11, there are 2 new tests: is sequence and is mapping, so we can use them to check if there is a single renderable and wrap it into a sequence before looping:

  {% set content = content is sequence ? content : [content] %}

However, we will need to update your dependencies in info.yml:

This change need to be done everywhere there is a loop on a slot:

button_group/button_group.twig:  {% for button in buttons %}
collection/collection.twig:    {% for item in items %}
collection_item/collection_item.twig:      {% for meta_item in meta_items_list -%}
collection_item/collection_item.twig:      {% for meta_item in meta_items_tags -%}
graphic_list/graphic_list.twig:  {% for item in items %}
grid_row/grid_row.twig:  {% for item in content %}
step_indicator/step_indicator.twig:    {% for completed_item in completed_items %}
step_indicator/step_indicator.twig:    {% for in_progress_item in in_progress_items %}
table/table.twig:{# Create unique attribute objects for each table group. #}
table/table.twig:    {% for colgroup in colgroups %}
table/table.twig:          {% for col in colgroup.cols %}

What else?

πŸ“Œ Task
Status

Active

Version

4.0

Component

Code

Created by

πŸ‡«πŸ‡·France pdureau Paris

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @pdureau
  • πŸ‡«πŸ‡·France pdureau Paris

    Also, in collection_item component, this:

    {% set is_list = meta_items_list is iterable and meta_items_list|keys|first == 0 %}
    {% set is_children = meta_items_list is iterable and meta_items_list|keys|first|first != "#" %}
    {% set meta_items_list = is_list or is_children ? meta_items_list : [meta_items_list] %}
    

    can be replaced by:

    {% set meta_items_list = meta_items_list is sequence ? meta_items_list : [meta_items_list] %}
    

    And this:

    {% set is_list = meta_items_tags is iterable and meta_items_tags|keys|first == 0 %}
    {% set is_children = meta_items_tags is iterable and meta_items_tags|keys|first|first != "#" %}
    {% set meta_items_tags = is_list or is_children ? meta_items_tags : [meta_items_tags] %}
    

    By:

    {% set meta_items_tags = meta_items_tags is sequence ? meta_items_tags : [meta_items_tags] %}
    

    We lose a bit of logic here because we are supposing ALL mapping or renderables arrays. In UI Patterns 2, we are sure of that. In UI Patterns 1.x, I don't know.

  • First commit to issue fork.
  • I tried replicating this. Drupal 11, set a view to display only article nodes. In row style option set to display body field using grid row component and plain text formatter. Everything worked as expected.

    Possible to share more information about your view configuration that might explain the exception?

  • First commit to issue fork.
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    So for views there are actually view formatters for the view + style row that can be used

    For example you can select the view to use "Accordion" component and pass the rows into the item slot
    Then have each row use the "Accordion item" component and pass whatever fields to it.

    Pushed up a small MR with the changes, but haven't tested their previews yet.

  • πŸ‡ΊπŸ‡ΈUnited States smustgrave
  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.71.5 2024