Unique id to recurring field in twig - Drupal 8

2.6k views Asked by At

I have a Drupal content type that uses multiple referenced entities of the same type (say, "related products")

I want to give the title field of every related product a unique ID. It can be the product name, an iterator, the ID of the product's node, whichever is easiest.

I created a twig template that overrides the title of said node in said content type: field--node--title--my-content-type.html.twig but I have no idea where to go from here.

I can add a custom id with

{% set attributes = attributes.setAttribute('id', 'customID') %}

but that's static, and would not be unique when the field is called multiple times.

{% set node = element['#object'] %} and {{ item.content['#node'].field_name.value }} as recommended here don't work for me.

If possible, I want to solve it twig-only, without any additional php code.

any pointers or suggestions are much appreciated

3

There are 3 answers

2
Kien Nguyen On BEST ANSWER

You can modify the code that loops through the items array.

For example, I added an iteration index:

field--node--title--my-content-type.html.twig

{# Here I coppied template from web/core/modules/system/templates/field.html.twig and modified it #}
{%
  set title_classes = [
  label_display == 'visually_hidden' ? 'visually-hidden',
]
%}

{% if label_hidden %}
  {% if multiple %}
    <div{{ attributes }}>
      {% for item in items %}
        <div{{ item.attributes }}>{{ item.content }}</div>
      {% endfor %}
    </div>
  {% else %}
    {% for item in items %}
      <div{{ attributes }}>{{ item.content }}</div>
    {% endfor %}
  {% endif %}
{% else %}
  <div{{ attributes }}>
    <div{{ title_attributes.addClass(title_classes) }}>{{ label }}</div>
    {% if multiple %}
    <div>
      {% endif %}
      {% for index, item in items %}                                     {# use index #}
        <span>{{ index }}</span>                                         {# and print it #}
        <div{{ item.attributes }}>{{ item.content }}</div>
      {% endfor %}
      {% if multiple %}
    </div>
    {% endif %}
  </div>
{% endif %}

Result:

enter image description here

0
Zsolt Balla On

The answer by Kien Nguyen did not exactly work for me as is, since while there were multiple referenced entities, but each of those had only one title, so the index always ended up being '0', which wasn't exactly a value I could use as a unique ID.

But building on his logic, It was now easy to arrive to a solution:

Instead of using the index as index, I used it as a key to access the value in item.content. (Since I was about to use item.content as the unique ID I had to get rid of the spaces, but in order to do that, I had to directly access the value in the item.content array.

In my scenario the item is a title for a 'related product' type of node, so it's

  • short enough to be used as a HTML id
  • unique (ie. there are no two different products with the same name)

so the

{% for index, item in items %}                                     {# use index #}
        <span>{{ index }}</span>                                         {# and print it #}
        <div{{ item.attributes }}>{{ item.content }}</div>

part in Kien's code became

{% for key, item in items %}
      <span id="{{element['#items'][key].value|replace({' ':''}) }}"></span>
      <div{{ item.attributes }}>{{ item.content }}</div>
    

in my implementation, which then provides me with a unique ID for every referenced node, as originally intended.

Thanks for your help, Kien!

0
Shawn W On

You can use twig random() for this and even set delimiters on the value, for example random(1, 50)

Source