I encounter a problem with the way Drupal renders Global Custom text.
I need to use Custom text field in my view to wrap fields. The body field has some "style" element inside the HTML but they are removed.
{% if field_titre_rubrique is defined and field_titre_rubrique|length %}
<div class="ancre" id="{{ field_ordre_rubrique }}">
<h1 class="ancreMenu">{{field_titre_rubrique}}</h1>
<div>
{% if body is defined %}
{{body}}
{% endif %}
{% if field_pdf is defined %}
{{field_pdf}}
{% endif %}
</div>
</div>
<div>{{ edit_node }}</div>
{% endif %}
Do I have a solution to keep "style" elements ?
You can use {{ body|raw }} but be sure that you can do this safely.
More about this topic: https://www.drupal.org/node/2296163
Related
Newbie question I presume: How do I change some CSS property (// change background image of parent div) of the parent element from within the logic in the HTML template? Do I really need to implement JS for this?
<div class="exercise-items-wrapper">
{% if error %}
{{ error }}
{% else %}
{% for x in exercise %}
<div class="exercise-item">
{{x.name}}
{% if x.primary_focus == 'CO' %}
// change background image of parent div
{% endif %}
{% if x.friend_verified %}
<img src="{% static 'main/images/fv.svg' %}" height="14px">
{% endif %}
<p id="exercise-level" class="exercise-level">lv. VII</p>
{% if x.video_verified %}
<img src="{% static 'main/images/vv.svg' %}" height="14px">
{% endif %}
</div>
{% endfor %}
{% endif %}
</div>
If by parent div you're referring to the div with class exercise-item, then the way I've always done this is to simply also write the if-then template block within the class attribute:
<div class="exercise-item {% if x.primary_focus == 'CO' %}special-background-class{% endif %}">
And then define special-background-class in your CSS. Admittedly it doesn't look nice to read, but it works and it's much more maintainable than anything that has to use JS, unless your JS is already well-integrated into your Django app.
I want to use an if statement in my twig for cycle - if object(variable) contains one element(row) - then add this html code snippet,
And here's what I'm trying,
{% for course in courses %}
<a href="{{ course.courseLink }}"class="courses">
<div class="picture"><img src="{{ asset('/bundles/dproc/assets/images/courses- example.jpg') }}" alt="news-1" title="news-1" /></div>
<div class="title"><h2>{{ course.courseTitle }}</h2></div>
<div class="info">
{{ course.courseContent }}
</div>
</a>
{% endfor %}
at the moment courses contains only one element. My task is to add a div element if it contains only one element.
How can I do that in twig?
You can use this function to check the length of an array
{% if courses|length == 1 %}
{# print div#}
{% endif %}
In the documentation there is a way in Symfony to customize a Individual field, based on the name/id of the widget.
{% form_theme form _self %}
{% block _product_name_widget %}
<div class="text_widget">
{{ block('field_widget') }}
</div>
{% endblock %}
{{ form_widget(form.name) }}
Here, the _product_name_widget fragment defines the template to use for the field whose id is product_name (and name is product[name]).
This works for a normal widget, but not if a widget is inside a collection. Because of the extra columns. Like this:
name="productbundle_product_type[foobar][1][value]" id="productbundle_product_type_foobar_1_value"
What is the way to make the Twig customization work inside the collection?
I thought something like this, but that doesn't work:
{% for db in edit_form.list %}
{% block _productbundle_product_type_foobar_{{ db.name }}_widget %}
<div class="text_widget">
{{ block('field_widget') }}
</div>
{% endblock %}
{% endfor %}
Even the following doesn't work:
{% _productbundle_product_type_foobar_1_value_widget %}
What is the way to make it work?
I was working on a project a couple of evenings ago and encountered precisely this problem - the solution I found is a pair of blocks that look like this (stripped of project-specific code):
{# Collection markup #}
{% block my_collection_widget %}
{# Customise collection row prototype for allow_add #}
{% if prototype is defined %}
{% set data_prototype = block('my_collection_item_widget') %}
<div id="my_prototype" data-prototype="{{ data_prototype }}" style="display: none"></div>
{% endif %}
{% for prototype in form %}
{{ block('my_collection_item_widget') }}
{% endfor %}
{% endblock my_collection_widget %}
{# Collection row markup #}
{% block my_collection_item_widget %}
{# Collection contains simple, single type #}
{{ form_errors(prototype) }}
{{ form_label(prototype) }}
{{ form_widget(prototype) }}
{# OR #}
{# Collection contains a compound type, render child types independantly #}
{{ form_errors(prototype.inner_widget) }}
{{ form_label(prototype.inner_widget) }}
{{ form_widget(prototype.inner_widget) }}
{% endblock my_collection_item_widget %}
I know this is old question, but maybe people still happening upon this. This is explained fragment naming for collections.
You use _entry_ in these cases in place of the collection element number. Use the instructions in the link for fragment naming, but this might vary. Sometimes 'type' is part of the fragment's name, sometimes first letter is upper case, sometimes lower case, etc. I would use a browser developer tool to find the actual name to make sure. You might also be able to customize the names used by adding the getBlockPrefix function to the form class.
Therefore, in your case above, the customized block might look something like:
{% block _ProductBundle_product_entry_widget %}
<div> {{ form_row(form.field)}} </div>
{% endblock %}
Where 'field' would be the name of a field in the element of your collection.
A few things here:
1. Documentation Error
The docs seem to be a bit off with CamelCase entities. As for 5.3 it should be: _taskManager_taskLists_entry_widget (instead of _task_manager_task_lists_entry_widget)
You can confirm the naming by dumping the form or form field: {{ dump(form) }} or {{ dump(form.yourField) }} in your template and then look for unique_block_prefix within the vars section.
2. Do NOT use the block overrides, macros are much more easy
It makes things absolutely more complicated than necessary. Simply define a macro:
{% import _self as formMacros %}
{% macro formatCollection(form) %}
<div class="form-group row">
<div>
{{ form_widget(form.field1) }}
{{ form_widget(form.field2) }}
{{ form_widget(form.field3) }}
</div>
</div>
{% endmacro %}
then simply run it on each collection:
{% for item in form.collectionItems %}
{{ formMacros.formatCollection(item) }}
{% endfor %}
3. Prototype
Get the prototype before rendering the collection field. You can store it in a variable.
{% set prototype = form.collection.vars.prototype %}
Then simply render it whenever you like using our macro:
<div data-js="collection" data-prototype="{{ formMacros.formatCollection(prototype)|e('html_attr') }}">
I have such hierarchy of twig files
my main (for controller) twig
{% extends "MainSiteBundle::layout.html.twig" %}
{% block footer_moderator_buttons %}
some buttons
{% endblock %}
{% block content_body %}
<p>hello moderator</p>
{{ include ('MainBlogBundle:_parts:postList.html.twig', {'postList': aPostDraft}) }}
{% endblock %}
postList.html.twig
<div class="post-list">
{% for postSingle in postList %}
{{ include ('MainBlogBundle:_parts:postSingle.html.twig', {'postSingle': postSingle}) }}
{% endfor %}
</div>
postSingle.html.twig
<div class="post">
<div class="post-header">
<a class="title" href="3">{{ postSingle.title }}</a>
</div>
<div class="post-meta">
<div>Date: {{ postSingle.date|date('D M Y') }}</div>
<div>Category: {{ postSingle.getCategory.getTitle }}</div>
<div>Author: {{ postSingle.getUser.username }}
</div>
</div>
<div class="post-body">
<div class="content">
<img width="450" height="200" src="#">
<div class="text">{{ postSingle.content }}</div>
</div>
</div>
<div class="post-footer">
{% block footer_moderator_buttons %}f{% endblock %}
<div>Views: 152</div>
<div>Comments: 1231</div>
<div>
<a class="link" href="#">More... </a>
</div>
</div>
</div>
As you can see last (postSingle.html.twig) has block "footer_moderator_buttons", so how can i change it from main twig (first one) ? Current is not working, what I need change \ do ?
In Twig 1.8 there is embed tag (http://twig.sensiolabs.org/doc/tags/embed.html).
You would have to remove the postList.html.twig file or work around it.
{% embed "MainBlogBundle:_parts:postSingle.html.twig" with {'postSingle': postSingle} %}
{% block footer_moderator_buttons %}
custom buttons here
{% endblock %}
{% endembed %}
So, you question is actually "I want to understand how\what twig can". Well, the answer to that question is: "It can't overwrite blocks from "main" to the smaller ones."
If you want to use twig, you have to stop thinking in php include() way where you make new files and you "PUT" components in them over and over again, components such as header, footer, menu etc.
In twig, you define main twig file with blocks which can be imagined as empty spaces which can, but do not have to, be overwritten. Surely, it still means you can have postList.html.twig as include in some file that extends MainSiteBundle::layout.html.twig. The same goes for postSingle.html.twig.
I think you catch the logic of twig except don't try to overwrite blocks from the wrong side - in this case, from MainSiteBundle::layout.html.twig to it's smaller portions.
how about this:
{% extends "MainSiteBundle::layout.html.twig" %}
....
{% block footer_moderator_buttons %}
{{ parent() }}
{% endblock %}
woops didnt put parent..
the {{ parent() }} will inherit {% block footer_moderator_buttons %}{% endblock %} from extended twig.
I use this piece of code in a big part of my templates:
{% if app.session.hasFlash('error') %}
<div class="error">
{{ app.session.flash('error') }}
</div>
{% endif %}
but the word error is changing. Could you give me idea how to avoid code duplication?
With include or macro I can change only the div class, but what about the word error in app.session.flash? And is there sense in doing this, or it's better to leave it that way?
You can include this with the "with" option. For example:
{% include 'AcmeDemoBundle:Tools:flash.html.twig' with {'flash':'error'} %}
And then in flash.html.twig do:
{% if app.session.hasFlash(flash) %}
<div class="{{flash}}">
{{ app.session.flash(flash) }}
</div>
{% endif %}