Twig: how to check the inner html content of a field

假装没事ソ 提交于 2020-01-23 12:25:32

问题


i have a single field and that field can have one or two lines of html:

<p>One line</p>

or:

<p>first line</p>
<p>Second line </p>

Using twig how can i check if the field has one or two

tags.

Example of what i want to do:

{% if item|length('<p>') = 1 %}
     <div class="one">{{ item }}</div>
 {% elseif item|length('<p>') = 2 %}
     <div class="two">{{ item }}</div>
 {% endif %}

Any ideas of how to accomplish this?

Update #1: What Honza said is true I want the parent div to have a class if there is only one line in the item and a different class if there are two lines in the item

Update #2 Here is the actual Markup in my twig file.

{%
  set classes = [
    'field',
    'field--name-' ~ field_name|clean_class,
    'field--type-' ~ field_type|clean_class,
    'field--label-' ~ label_display,
  ]
%}
{%
  set title_classes = [
    'field__label',
    label_display == 'visually_hidden' ? 'visually-hidden',
  ]
%}

  <div{{ attributes.addClass(classes) }}>

    <div{{ title_attributes.addClass(title_classes) }}>{{ label }}</div>

    {% if multiple %}  <div class="field__items"> {% endif %}

    {% for item in items %}
      <div{{ item.attributes.addClass('field__item') }}>{{ item.content }}</div>
    {% endfor %}

    {% if multiple %} </div> {% endif %}
  </div>

i want the field__item to have a class when it has one <p> tag and a different class when it has two, I know by fact it will be <p> tags but the content of the <p> tag varies i just use first line and second line as an example but the content is generated by the user after they fill the field whether the use one line or two lines.

Alvin Bunk - using your code from Edit two got close but it still would output the classes as 0 regardless and i'm not sure why because i see in your twigfiddle file it worked, maybe it is because it's Drupal 8. the fallowing was how i integrated your code into the template:

 <div{{ attributes.addClass(classes) }}>

    <div{{ title_attributes.addClass(title_classes) }}>{{ label }}</div>

    {% if multiple %} <div class="field__items"> {% endif %}

    {% set count = item|split('</p>') %}

    {% for item in items %}

      <div class="{{ count|length -1 }}">{{ item.content }}</div>

    {% endfor %} 

    {% if multiple %} </div> {% endif %}

  </div> 

I don't know what i am doing wrong but it always comes out as class="0" i have also tried with "item.content" and "item.content|raw" but nothing.

Here is the dump output:

array(1) {
  [0]=>
  array(2) {
    ["content"]=>
    array(4) {
      ["#type"]=>
      string(14) "processed_text"
      ["#text"]=>
      string(52) "<p>CGS-2181-3105-9090</p>
<p>CGS-2181-3105-9090</p>"
      ["#format"]=>
      string(15) "restricted_html"
      ["#langcode"]=>
      string(3) "und"
    }
    ["attributes"]=>
    object(Drupal\Core\Template\Attribute)#2953 (1) {
      ["storage":protected]=>
      array(0) {
      }
    }
  }
}

Update #3

Based on the dump above i can get the html value of the field using {{ item.content["#text"] }} which outputs <p>CGS-2181-3105-9090</p> <p>CGS-2181-3105-9090</p> but i dont know how to iterate through it, i tried to set a variable {% set count = '<p>' in item.content["#text"] %} and then check the length like {{ count|length }} but i always get 1 regardless.

Update #4:

Using a variation of the code from Alvin Bunk i was able to finally get it to output a number here is the markup that gets the numbers of tag correctly:

 {% for item in items %}

          {% set count = item.content["#text"]|split('</p>') %}    

      <div class="{{ count|length -1 }}">{{ item.content }}</div>

    {% endfor %}

I moved the set variable below for loop and added the object where the strings exist from the dump and now it counts properly.


回答1:


You haven't provided enough information, however I'll presume some things:

Item is a string, like so:

<p>first line</p><p>Second line</p>

Then you can use the following Twig code:

{% set lines = item|split('</p>') %}

{% for element in lines if element != '' %}
    <div class="{{ loop.index }}">{{ element|raw }}</p></div>
{% endfor %}

In the above, I take the item string and split into an array called lines. And then I do a for loop of the lines elements, and set the class to the loop index (which is one based). I output as raw html.

You'll notice since I split on '</p>', the array lines will contain one last element which is null; so in my for I have to add if element != ''.

Here is the twigfiddle for you to see it working in action.


EDIT #2 - Based on comments.

In that case, this should work:

{% set item = '\n<p>first line</p>\n<p>Second line</p>\n' %}

{% set count = item|split('</p>') %}

<div class="{{ count|length -1 }}">{{ item|raw }}</div>

I updated my twigfiddle so you can see the change.


EDIT #3

You missed one change, you need to split items not item:

<div{{ attributes.addClass(classes) }}>

    <div{{ title_attributes.addClass(title_classes) }}>{{ label }}</div>

    {% if multiple %} <div class="field__items"> {% endif %}

    {% set count = items|split('</p>') %}

    {% for item in items %}
      <div class="{{ count|length -1 }}">{{ item.content }}</div>
    {% endfor %} 

    {% if multiple %} </div> {% endif %}

  </div>

EDIT #4

Your set for count needs to be outside the loop. Try this:

{% set count = item.content["#text"]|split('</p>') %}  
{% for item in items %}
      <div class="{{ count|length -1 }}">{{ item.content["#text"] }}</div>
{% endfor %}



回答2:


Another option is to make a Twig extension for counting paragraphs, but it's maybe an overkill for such a task:

EDIT - updated for Drupal

namespace Drupal\twig_extension_parCount\TwigExtension;

use Drupal\Core\Template\TwigExtension;

class parCountExtension extends TwigExtension
{
    public function getFunctions() {
        return array(
            'parCount' => new \Twig_Function_Function(array('Drupal\twig_extension_parCount\TwigExtension\ParCountExtension', 'parCount')),
        );
    }

    public function getName() {
        return 'twig_extension_parCount.parCount_extension';
    }

    public static function parCount($str)
    {
        return substr_count($str, '<p>');
    }
}

And then in template itself

{%  if (parCount(item) == 1) %}
   <div class="one">
{% elseif (parCount(item) == 2) %}
   <div class="two">
{% endif %}
{{ item }}</div>


来源:https://stackoverflow.com/questions/42143752/twig-how-to-check-the-inner-html-content-of-a-field

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!