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...
Related
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
I have a little problem in twig to render symfony forms,
so, first I will explain the context of it.
In Twig, blocks are defined in a certain order on a template:
{# base.layout.html.twig #}
{% block firstBlock %}
{% endblock firstBlock %}
{% block secondBlock %}
{% endblock secondBlock %}
And when we extends this template we can write this:
{# child.layout.html.twig #}
{% embed "base.layout.html.twig" %}
{% block secondBlock %}
{{ form_widget(form.submit_button) }}
{% endblock secondBlock %}
{% block firstBlock %}
{{ form_widget(form.some_field) }}
{{ form_rest(form) }}
{% endblock firstBlock %}
So the problem is with the form() functions in twig which renders Symfony forms.
I am trying to generate a submit button at the very end of a modal window
but the problem is that form_rest() renders all parts of the form not already rendered.
There is a little fix to avoid form_rest to render form.submit_button, it's to set form.submit_button as an already rendered field with:
{% do form.submit_button .setRendered %}
But with this form.submit_button is never rendered
Of course the finality of all this is to don't remove the form_rest instruction.
So I search something to unset rendered value of form.submit_button after the form_rest instruction or even better a way to choose the order of blocks generation of a template.
Like this:
{% block secondBlock with(1) %}
{{ form_widget(form.submit_button) }}
{% endblock secondBlock %}
{% block firstBlock with(2) %}
{{ form_widget(form.some_field) }}
{{ form_rest(form) }}
{% endblock firstBlock %}
Thank you for your help !
If it is just for a submit button, you can remove it from your form type and write it in html, it is'nt a problem, and it will work.
The problem is that you render first the rest (including the button), and after you try to render the button but it is already rendered...
Of course, your html button must be inside < form > tags.
If you want to keep your submit button from your form type,
1 solution is to move it using some javascript ...
2 solution is to mark it as rendered (as you have done), and write the exact html of your submit button in the place you want.
[edit]
You can also render every field of your form in the first block, render your submit button in the second block, and put form_rest after all these (as all the fields have been rendered, it will not have something to render,
this is a solution also)
If that's just a matter of a submit button that has no logic and no mapping at all, the easiest way is to render your submit button in HTML directly and removing it from your form.
<input type="submit" value="Submit"> {# ¯\_(ツ)_/¯ #}
Another solution is to put your modal in a modal_layout.html.twig, and then use the embed tag that is exactly made for this kind of issues.
modal_layout.html.twig
<div class="modal">
<div class="form">
{% block form_part %}{% endblock %}
</div>
<div class="submit pull-right">
{% block submit_part %}{% endblock %}
</div>
</div>
your_page.html.twig
{% embed 'modal_layout.html.twig' %}
{% block submit_part %}
{{ form_row(form.submit_button) }}
{% endblock %}
{% block form_part %}
{{ form(form) }} {# won't render submit again #}
{% endblock %}
{% endembed %}
But IMO the second solution, even if it appears cleaner, does not worth it for a stupid submit button.
Cheers
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'
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.
Twig uses the {{ }}, {% %}, {# #} delimiters.
But how can I display {{ }} in a Twig template?
I'm not talking about HTML escaping.
I ask the question as I want to include a mustache template in my Twig template so that I will fill with data coming from an AJAX call.
The easiest way is to output the variable delimiter ({{) by using a variable expression:
{{ '{{' }}
Alternatives (used when you have to escape too much) are raw (verbatim since 1.12) blocks:
{% raw %}
<ul>
{% for item in seq %}
<li>{{ item }}</li>
{% endfor %}
</ul>
{% endraw %}
Actually, it's quite well documented.
The Twig documentation gives two suggestions. The first is simply to output a string:
{{ '{{' }}
Otherwise, if you want to output a long section (it sounds like you do) you can use the raw tag:
{% raw %}
your mustache content here
{% endraw %}
{% block body %}
<table class="table table-striped">
{% for temp in data %}
<tr>
<td>{{temp.fname}}</td>
<td>{{temp.lname}}</td>
</tr>
{% endfor %}
</table>
{% endblock %}