Twig macros+blocks or something? - twig

Im new to Twig. Is there something similar to Jade's mixins with nested blocks?
I mean something like this:
mixin button(text)
.btn
.txt= text
.dropdown
block
+button("button")
+button("sub1")
+button("sub1-1")
+button("sub1-2")
+button("sub2")
+button("sub2-1")
.custom1 blah-blah
+button("sub3")
+button("sub3-1")
+button("sub3-2")

I found some kind of solution.
I have just splitted macro into 2+ macros.
{% __btns.twig %}
{% macro btn1_opening(text) %}
<div class="button1">
<div class="text">{{ text }}</div>
<div class="dropdown">
{% endmacro %}
{% macro btn1_closing() %}
</div>
</div>
{% endmacro %}
{# main.twig #}
{% import "__btns.twig" as btns %}
{{ btns.btn1_opening("I am button") }}
<div class="something-inside-dropdown">
{% include "somefile.twig" %}
</div>
{{ btns.btn1_closing() }}
So, in this case even if i need multiple blocks inside of my macro i can just write some HTML between opening, intermediate and closing macros.

Related

Using Twig to declare template and pass in additional content between the parent template's block

I have the following code that I repeat multiple times in my layout:
<div id="hi">
<div class="howAreYou">
<p class="fineTYForAsking">
<!-- additional HTML logic goes here -->
</p>
</div>
</div>
How can I put in the above html into a single Twig template, and then use that template and put in my additional specific html in the <!-- additional HTML logic goes here --> section?
You could just define blocks and embed the template where ever you want
partial.twig.html
<div id="{{ id | default('hi') }}">
<div class="howAreYou">
<p class="fineTYForAsking">
{% block content %}
{% endblock %}
</p>
</div>
</div>
template.twig.html
{% embed "partial.html.twig" with { 'id' : 'foo' } %}
{% block content %}
Lorem Ipsum
{% endblock %}
{% endembed %}
You could also use an embed in a for-loop. Variables known inside the loop, are also know in the embedded file, e.g.
item.html.twig
<div{% if item.id|default %} id="{{ item.id }}"{% endif %}>
<div class="howAreYou">
<p class="fineTYForAsking">
{% block title %}
{% if item.title is defined %}
<h1>{{ item.title }}</h1>
{% endif %}
{% endblock %}
{% block content %}
{% if item.content is defined %}
<p>{{ item.content }}</p>
{% endif %}
{% endblock %}
</p>
</div>
</div>
template.html.twig
{% for item in items %}
{% embed "item.twig" %}
{% endembed %}
{% endfor %}
demo

How to reduce duplication in Twig template

I have an if/else condition in a twig template which switches the out tag of a block of code, however the inner block is the same. Is there a way to reduce the duplication without creating a separate file?
This is what I have at the moment:
{% if condition %}
<a href="">
{{ content }}
</a>
{% else %}
<span>
{{ content }}
</span>
{% endif %}
I was hoping to do something such as:
{% if condition %}
<a href="">
{% include mycontent %}
</a>
{% else %}
<span>
{% include mycontent %}
</span>
{% endif %}
{% mycontent %}
{{ content }}
{% endmycontent %}
Is such a thing possible?
If you don't want to use extra files you could use macro's :
{% import _self as macro %}
{% macro foo(content) %}
{{ content }}
{% endmacro %}
{% for condition in [0, 1, 0, 1, ] %}
{% if condition %}
{{ macro.foo('Bar') }}
{% else %}
<span>{{ macro.foo('Bar') }}</span>
{% endif %}
{% endfor %}
fiddle
What you want to do has to be done using the normal syntax. an extra file. and include this file.
But if u want to do this without extra file. use the {% set variablecontent = "put content here" %} and then in your "{% mycontent %}" part u put {{ variablecontent }}
hope this helps

Symfony / a2lix_translations / customize

can someone help me.
How can I modify default template to bootstrap version?
Because input's doesn't have a class "form-control".
Here is defaul:
{% block a2lix_translations_widget %}
{{ form_errors(form) }}
<div class="a2lix_translations tabbable">
<ul class="a2lix_translationsLocales nav nav-tabs">
{% for translationsFields in form %}
{% set locale = translationsFields.vars.name %}
<li {% if app.request.locale == locale %}class="active"{% endif %}>
<a href="#" data-toggle="tab" data-target=".{{ translationsFields.vars.id }}_a2lix_translationsFields-{{ locale }}">
{{ locale|capitalize }}
{% if form.vars.default_locale == locale %}[Default]{% endif %}
{% if translationsFields.vars.required %}*{% endif %}
</a>
</li>
{% endfor %}
</ul>
<div class="a2lix_translationsFields tab-content">
{% for translationsFields in form %}
{% set locale = translationsFields.vars.name %}
<div class="{{ translationsFields.vars.id }}_a2lix_translationsFields-{{ locale }} tab-pane {% if app.request.locale == locale %}active{% endif %} {% if not form.vars.valid %}sonata-ba-field-error{% endif %}">
{{ form_errors(translationsFields) }}
{{ form_widget(translationsFields) }}
</div>
{% endfor %}
</div>
</div>
{% endblock %}
{% block a2lix_translationsForms_widget %}
{{ block('a2lix_translations_widget') }}
{% endblock %}
I have no idea what should I insert/delete/modify :(
Thanks
I have done a custom form template for a2lix_translations with bootstrap(full code is too long and not optimal to paste here) But to get the classes I need like form-control into the widgets I have done the following:
{%for field in translationsFields%} {# further break the transliationsfields into individual inputs #}
{%if field.vars.attr is not empty and field.vars.attr['class'] is defined and field.vars.attr['class']=="tinymce"%}
{{form_widget(field ,{'attr':{'class':' tinymcertl'}} )}}
{%else%}
{{form_widget(field,{'attr':{'style':'direction:rtl','class':class~' form-control'}} )}}
{%endif%}
{%endfor%}
The ugly code above is basically saying, if the widget already has a class, add the class form-group to it. If the widget does not have a class at all, set the class to be form-group. I have done that if statement to avoid null pointers since if I try to reference the form class and there isn't one, the code will crash. And if I just do set class to form-group, it will erase the previous classes.
I hope this helps. My full code might not be helpful to you because the languages I was working with involved left to right language and right to left languages, so a lot of conditions had to be implemented to orient my page in the right direction, which is messy and you might not need...
PS: this was done on symfony 2.7 or so. Did not test on symfony 3.
in my case sf 3.2 i just did this change in my config.yml and all forms are bootstraped :
# app/config/config.yml
twig:
//....
form_themes:
- 'bootstrap_3_layout.html.twig'

Twig embed block not working when its within a loop?

I need to place a twig template into my page and place another twig template inside it.
In page.twig:
{% embed "parent.twig" %}
{% block something %}
{% include "child.twig" %}
{% endblock %}
{% endembed %}
In parent.twig:
{% set array = ['', '', '']
%}
<div class="parent">
{% for i in array %}
<div class="parent__item">
{% block cardBoard %}
{% endblock %}
</div>
{% endfor %}
</div>
The problem is that the block doesn't work when its within a loop. I can edit page.twig all I like but I would rather not change parent.twig if possible as its consumed by other applications.
Why do you put a block inside a for loop ? You can't have 2 blocks defined with the same name.
In your case it will try to put this in your template 3 times :
<div class="parent__item">
{% block cardBoard %}
{% endblock %}
</div>
This will create a 500 server error :
The block 'cardBoard' has already been defined line '' in :parent.twig at line ''.
If you really want to have content depending on the values in your array, put the block opening and closing outside the for loop.
Like this for example :
{% set array = ['', '', '']%}
<div class="parent__item">
{% block cardBoards %}
{% for i in array %}
<div class="cardBoard{{ i }}>
</div>
{% endfor %}
{% endblock %}
</div>

Inline form template/theme rendering where declared

I have this simple form where I need a custom template for a field to render something right next to the <input> tag. Since I won't be needing this anywhere else, I thought I'd put it right in the same template as the form like suggested here:
{% form_theme form _self %}
{% block text_widget %}
{{ block('form_widget_simple') }}
something
{% endblock %}
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
That's pretty much the whole template (to be used with ajax, hence no surrounding markup).
The issue now is, "something" gets rendered right at the beginning of the output where the block text_widget is declared, as would any other block. Its rendered fine in the form next to the <input>:
something
<form name="form" method="post" action="">
<table id="form"><tr>
<td> <label for="form_Search" class="required">Search</label></td>
<td> <input type="text" id="form_Search" name="form[Search]" required="required" autofocus="autofocus" />
something
</td>
</tr><tr style="display: none">
<td colspan="2"><input type="hidden" id="form__token" name="form[_token]" value="dUwdoiz9vo1TJTRjvyUcz9Rwd-D7pTvqUH-R0zCtg28" /></td>
</tr></table>
</form>
This obviously makes inline theming completely unusable, so I think I might be doing something wrong...
How do I get rid of that extra "something" at the beginning?
Having the question already written up and also solved the problem, I might as well answer:
The solution is to derive the template from a dummy base template to swallow any output that's outside of blocks defined in the base template:
{# empty.html.twig #}
{% block content %}
{% endblock %}
And for the actually needed template:
{% extends 'empty.html.twig' %}
{% form_theme form _self %}
{% block text_widget %}
{{ block('form_widget_simple') }}
something
{% endblock %}
{% block content %}
{{ form_start(form) }}
{{ form_widget(form) }}
{{ form_end(form) }}
{% endblock %}
One probably wouldn't think twice about it when customizing a field in a regular template that already uses inheritance, but this way it feels like a hack...

Resources