2

I have a Drupal 8 site with a node type exposing a "difficulty level" field which is an integer choosen from a list (1 to 5). Current onsite display is : "difficulty: 3". I would like to replace the value "3" by three black stars and two white ones to picture "3/5" (done via CSS background images).

In field--field-difficulty.html.twig I have replaced item.content by:

{% for i in range(1, 5) %}
  {% if (loop.index <= item.content) %}
    <span class="active">*</span>
  {% else %}
    <span class="active"> </span>
  {% endif %}
{% endfor %}

But this keep giving me five * displayed, just like if the {% if %} statement was always true. Can someone give me a hint on this please ?

2 Answers 2

2

For the field template there are two approaches to get the integer number from a field:

Node object

{% set difficulty = element['#object'].field_difficulty.value %}
{% for i in range(1, 5) %}
  {% if i <= difficulty %}

Find the rendered number

You can try to find the number in #markup:

{% if loop.index <= item.content['#markup'] %}

The node object is the better approach, because the way how the number is rendered can change when updating the code or changing the configuration.

5
  • Hi ! {{ element['#object'].field_difficulty.value }} does not print the value {{ item.content['#markup'] }} does print the field value {{ item.content }} does to However, none of the {% if ... %} {% else %} work: every solution goes in the if, not in the else, giving me 5/5 rendering no matter the real field value. Do you have an idea why ? May it be that the value is considered as a string, so the comparison compare an integer (loop.index) with the item.content string ? Dec 17, 2016 at 9:21
  • That's the problem with the rendered output, it is supposed to be printed in the browser, not to be used for logic. But you should be able to find the raw value in #object. Try {{ element['#object'].id }} to check if you have an object and that the id is the one you are looking for. Then check the correct spelling of the field. You find the machine name of the field when you configure the content type. And twig doesn't need parentheses in if. I've removed them in the answer.
    – 4uk4
    Dec 17, 2016 at 9:48
  • I have done exactly so. By printing both loop.index, and element['#object'].field_difficulty.value I can see the values are correct and the loop is run correctly. The whole thing is that if loop.index <= element['#object'].field_difficulty.value is not evaluated properly... always true. Dec 17, 2016 at 10:18
  • 1
    what if you set a variable {% set difficulty = element['#object'].field_difficulty.value %} before you start the loop and compare this to i, this looks cleaner and is easier to debug?
    – 4uk4
    Dec 17, 2016 at 10:37
  • 1
    Perfect ! Because I wanted it generic in field--list-integer.html.twig template, I had to tweak it a bit to not actually having the field_name in the template. Here is the full solution I used : {% set fieldname = attribute(element['#object'], element['#field_name']) %} {% for i in range(1, 5) %} {% if i <= fieldname.value %} <span class="active">*</span> {% else %} <span class="not-active"> </span> {% endif %} {% endfor %} Dec 17, 2016 at 11:39
1

Maybe add the field value or content to a class, and then use that selector to set a background image.

{% for item in items %}
  {# set a new variable #}
  {% set star_class = 'star' ~ item.content %}
  {# add class to attributes for the item, item.content may not be appropriate here. Use kint/dump to see more info on item variable. #}
  <span{{ item.attributes.addClass(star_class)}}>{{ item.content }}</span>
{% endfor %}

https://www.drupal.org/docs/8/theming-drupal-8/using-attributes-in-templates

Then you can apply your background, width, text-indent, display, etc... to allow for the additional widths for styles. Probably done in a pseudo-element.

3
  • This approach would work, but for what I understand it would need 5 different images for the 5 cases: 1/5, 2/5, 3/5... This is why I would rather generate 3 span "active" and 2 "inactive" for representing 3/5 with the CSS background-image technique. Dec 17, 2016 at 9:14
  • Or 1 image as a spritesheet.
    – mradcliffe
    Dec 17, 2016 at 13:24
  • Yes, a per choosen solution. The difference is chosen solution needs only a 2 star sprite: one active star, one inactive. Dec 19, 2016 at 18:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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