I'm learning Symfony2. Currently, I'm trying to render a form label in a twig template. The label includes an html tag, that is not rendered correctly in my twig file.
Here follows the piece of code where the form field is created:
$builder->add('zipcode', 'integer', array(
'label' => '<abbr title="Zone Improvement Plan">CAP</abbr> code',
));
In the twig file I render the field label as follows:
{{ form_label(form.zipcode) }}
I tried the raw, escape, e filters, but the results provided in my html page is always the string
<abbr title="Zone Improvement Plan">CAP</abbr> code
and not the corresponding HTML code!
Any suggestion?
Thanks in advance!
Later I found the solution.
The solution is to disable the autoescape within the label block provided by Symfony at path:
symfony / src / Symfony / Bridge / Twig / Resources / views / Form / form_div_layout.html.twig
So, in your twig file you have to put the following lines outside the form:
{% form_theme form _self %}
{% block generic_label %}
{% spaceless %}
{% if required %}
{% set attr = attr|merge({'class': attr.class|default('') ~ ' required'}) %}
{% endif %}
<label{% for attrname,attrvalue in attr %} {{attrname}}="{{attrvalue}}"{% endfor %}>{% autoescape false %}{{ label|trans }}{% endautoescape %}</label>
{% endspaceless %}
{% endblock %}
From JeanValjean himself :
{% autoescape false %}{{ form.zipcode.vars.label | trans }}{% endautoescape %}
And to generalize this behaviour to your whole app, you can override the form block for labels :
{% block generic_label %}
{% spaceless %}
{% if required %}
{% set attr = attr|merge({'class': attr.class|default('') ~ ' required'}) %}
{% endif %}
<label{% for attrname,attrvalue in attr %} {{attrname}}="{{attrvalue}}"{% endfor %}>
{% autoescape false %}{{ label|trans }}{% endautoescape %}
</label>
{% endspaceless %}
{% endblock %}
To disable the autoespace filter just to render a variable is not the best thing because when you read the code it's not really clear.
So, instead of :
{% autoescape false %}{{ label|trans }}{% endautoescape %}
You can use :
{{ label|trans|raw }}
Related
[ Symfony 4 ]
I've this template code in Symfony:
{{ form_widget(registrationForm.username, {'attr': {'class': 'form-control'}}) }}
{{ form_errors(registrationForm.username) }}
Instead of just displaying error text, it's generating a list item like this:
<ul><li> Username already exists </li></ul>
How to not have it generate this list item and just get the text?
I guess it is correct behavior, cause you can have multiple errors for one field for example "Username is too short" and "Field Username contains inappropriate characters", but to get only first error you can use:
{{ form_errors(registrationForm.username|first) }}
Or you can customize your form_errors rendering, first create file for form_errors, for example your_form/custom_form_errors.html.twig :
{% block form_errors %}
{% spaceless %}
<div class="error">{{ errors|first }}</div>
{% endspaceless %}
{% endblock %}
And after that include it to your view file:
{% form_theme form 'your_form/custom_form_errors.html.twig' %}
...
{{ form_errors(registrationForm.username) }}
just to extend #Andrii Filenko 's answer. You can modify the output the form_errors or any other form twig function pretty easily. it's called custom theming in Symfony.
Consider this:
// templates/register.html.twig
{% extends "base.html.twig" %}
{% form_theme registrationForm _self %}
{% block form_errors %}
{% spaceless %}
{% if errors|length > 0 %}
<ul class="changed list">
{% for error in errors %}
<li>{{ error.message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endspaceless %}
{% endblock form_errors %}
{% block body %}{% endblock %}
Output:
<ul class="changed list"><li> Username already exists </li></ul>
Using Symfony2.3.4 with Twig.
Say I´m trying to add, for example, a colon (:) and, if required, an asterisk (*) to every label of every field in a form generated by Symfony2's CRUD. For this I'm using a twig template to inherit Symfony2's main template form_div_layout.html.twig.
So far:
//config.yml
twig:
form:
resources:
- ::my_form_layout.html.twig
//my_form_layout.html.twig
{% block form_label %}
{% spaceless %}
{% if label is not sameas(false) %}
...
{% set asterisk = '<sup><i title="Campo obligatorio"
class="glyphicon-asterisk" style="color: red; font-size:
8px"></i></sup>' %}
<label {% for attrname, attrvalue in label_attr %}
{{ attrname }}="{{ attrvalue }}"{% endfor %}>
{{ label|trans({}, translation_domain) }}: {% if required %}
{{ asterisk|raw }} {% endif %}
</label>
...
{% endif %}
{% endspaceless %}
{% endblock form_label %}
Problem is this way when I render, for example, a choice-type field for selecting the sex of a person, with expanded and required set to TRUE, the colon (:) and the asterisk (*) appear next to the word Sex AND the words Male and Female as well.
How can I make the template differenciate between the parent and the two children, so the colon and the asterisk appear only after the word Sex.
Thanx
This is how I've done something similar. Modify the 'choice_widget_expanded' block a bit in your custom form layout:
// update this row: {{ form_label(child) }}
{{ form_label(child, child, {'exclude_additions': 'true'}) }}
And update your 'form_label' to check whether this value is defined:
{{ label|trans({}, translation_domain) }}{% if exclude_additions is not defined %}: {% if required %}
{{ asterisk|raw }} {% endif %} {% endif %}
I have a symfony page where I display a form, and I would like to add an
* in the labels of all fields that are required.
So I have my form.php.twig, that looks like this:
{% extends "::layout.php.twig" %}
{% block body %}
<div class="row">
{% use 'form_div_layout.html.twig' with form_label as base_form_label %}
{% block form_label %}
{{ block('base_form_label') }}
{% if required %}
<span class="required" title="This field is required">*</span>
{% endif %}
{% endblock %}
</div>
{% endblock %}
I followed the exact documentation of the symfony cookbook on how to customise labels, which is http://symfony.com/doc/current/cookbook/form/form_customization.html#cookbook-form-theming-methods.
But I keep getting this error
Variable "label" does not exist in form_div_layout.html.twig at line 206
I don't have any label variable in the code of my form.php.twig so I don't see why I get this error. And when I remove the
{{ block('base_form_label') }}
I get
Variable "required" does not exist in ATPlatformBundle:Session:create.php.twig
Can anyone help me on this? I don't see where is my mistake? I am not looking to customise it with css, but to add the * .
I have checked the form_div_layout.html.twig at line 206 and this is what there is
{%- block form_label -%}
{% if label is not sameas(false) -%}
{% if not compound -%}
{% set label_attr = label_attr|merge({'for': id}) %}
{%- endif %}
{% if required -%}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' required')|trim}) %}
{%- endif %}
{% if label is empty -%}
{%- if label_format is not empty -%}
{% set label = label_format|replace({
'%name%': name,
'%id%': id,
}) %}
{%- else -%}
{% set label = name|humanize %}
{%- endif -%}
{%- endif -%}
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ translation_domain is sameas(false) ? label : label|trans({}, translation_domain) }}</label>
{%- endif -%}
{%- endblock form_label -%}
Thank you in advance.
Did you try defining the label from inside your form builder?! The below field is a required one because unless you mention required => false, your field will be rendered as required.
Something like:
->add('name', 'text', array('label' => '* name'))
With Twig, you should have to test the existence of a variable before using it:
Variable "required" does not exist
{% if required is defined and ... }
You need to test this because you field isn't always required.
if you want further information, you have this page of the documentation:
http://twig.sensiolabs.org/doc/tests/defined.html
Ok, so at the end, I didn't manage to change labels within my form.php.twig (which is the template I use to display my form), but I used another technique.
I created a new file named fields.php.twig, which I put in MyBundle/Resources/views/Form.
At the beginning of my fields.php.twig, I then added
{% extends 'form_div_layout.html.twig' %}
and below it, I added
{% block form_label %}
{{ parent() }}
{% if required %}
<span> * </span>
{% endif %}
{% endblock form_label %}
Then in my form.php.twig, I added
{% form_theme form 'MyBundle:Form:fields.php.twig' %}
{{ form_start(form) }}
Myform here with {{ form_label(form.property) }}
{{ form_errors(form.property) }}
{{ form_widget(form.property) }}
{{ form_end(form) }}
It works perfectly, but I had to create the fields.php.twig.
I'd like to create a custom template in twig to render a form field.
Example:
{{ form_row(form.field) }}
This can be overriden by form theming
{% block form_row %}
... custom code
{% endblock form_row %}
What I would like to do is this:
{% block custom_row %}
... custom code
{% endblock custom_row %}
and use it like this:
{{ custom_row(form.field }}
however, this throws an exception that method custom_row is not found.
My understanding is that this can be done with Twig extension, but I don't know how to register a block to be a function.
Update
what I actually want:
I use twitter bootstrap and a bundle which overrides all the form themes. And it renders a div around a radio, so it can't be inlined. So I wanted to do something like this:
copy their template and get rid of the div:
{% block inline_radio_row %}
{% spaceless %}
{% set col_size = col_size|default(bootstrap_get_col_size()) %}
{% if attr.label_col is defined and attr.label_col is not empty %}
{% set label_col = attr.label_col %}
{% endif %}
{% if attr.widget_col is defined and attr.widget_col is not empty %}
{% set widget_col = attr.widget_col %}
{% endif %}
{% if attr.col_size is defined and attr.col_size is not empty %}
{% set col_size = attr.col_size %}
{% endif %}
{% if label is not sameas(false) %}
{% if not compound %}
{% set label_attr = label_attr|merge({'for': id}) %}
{% endif %}
{% if required %}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' required')|trim}) %}
{% endif %}
{% if label is empty %}
{% set label = name|humanize %}
{% endif %}
{% set label_attr = label_attr|merge({'class': (label_attr.class|default('') ~ ' radio-inline')|trim}) %}
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>
{{ block('radio_widget') }}
{{ label|trans({}, translation_domain) }}
</label>
{% else %}
{{ block('radio_widget') }}
{% endif %}
{{ form_errors(form) }}
{% endspaceless %}
{% endblock inline_radio_row %}
and then
{{ inline_radio_row(form.field) }}
I ended up just overriding the whole theme, and added ifs around the div in question, a the class (radio-inline). But I'm still wondering if there's a way to make this work. Seems like it makes you work so hard for something so simple.
Update 2
I found the functionality:
class FormExtension extends \Twig_Extension
{
public function getFunctions()
{
return array(
'inline_radio_row' => new \Twig_Function_Node(
'Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode',
array('is_safe' => array('html'))
),
);
}
}
This does exactly what I want, but it says it's deprecated. Anyone knows an updated version of how to use this?
Update 3
Similar functionality can be also achieved with http://twig.sensiolabs.org/doc/tags/include.html
You can use the twig functions for each part of a form row:
form_label(form.field)
form_widget(form.field)
form_errors(form.field)
For example:
<div class="form_row">
{{ form_label(form.field) }} {# the name of the field #}
{{ form_errors(form.field) }} {# the field #}
{{ form_widget(form.field) }} {# the errors associated to the field #}
</div>
You can use form theming.
Step by step:
1. Form Type Class
Check the name in your class
public function getName() {
return 'hrQuestionResponse';
}
2. Include a custom theme in your template
{% form_theme form 'InterlatedCamsBundle:Form:fields.html.twig' %}
3. Find the block
Can be quite difficult. For the bootstrap bundle, as you seem to have found it is in ./vendor/braincrafted/bootstrap-bundle/Braincrafted/Bundle/BootstrapBundle/Resources/views/Form/bootstrap.html.twig and you have found the block radio_row. I have been finding the block by putting output in the source template and overriding more blocks than I need. In 2.7 there is a theme 'rendering call graph'.
4. Override the block
Copy the block from the master template and call it replace the standard term with the name of in the FormType found in step 1.
Don't forget to also change the endblock name.
e.g.
{% block hrQuestionResponse_widget %}
hrQuestionResponse_row
{% spaceless %}
{% set class = '' %}
...
{% endspaceless %}
{% endblock hrQuestionResponse_widget %}
In your case because you can only call form_widget() you will need to override _widget. You could extract only the content that you need, or you can override the block chain to radio_row.
I want to theme my form so that the field's label show the current locale, something like
Name (en) :
So I would like to rewrite block generic_label like that :
{# form_theme.html.twig #}
{% block generic_label %}
{% spaceless %}
{% if required %}
{% set attr = attr|merge({'class': attr.class|default('') ~ ' required'}) %}
{% endif %}
<label{% for attrname,attrvalue in attr %} {{attrname}}="{{attrvalue}}"{% endfor %}>{{ label|trans }} (app.session.locale)</label>
{% endspaceless %}
{% endblock %}
and import it in my template :
{% form_theme options 'myBundle:Object:form_theme.html.twig' %}
but the app variable is not accessible in the form template.
How can I pass a variable to a form theme ?
In current version of twig (as for 2016) it is possible.
In your template use the following like this:
{{ form_row(form.content, {'testvar' : 'this is test variable'}) }}
Then, in your theme file, just use:
{{testvar}}
of course instead of form.content you will use the field name you need.
Cheers,
Chris
You need to create a form extension in order to get it done. Take a look at
http://toni.uebernickel.info/2011/11/25/how-to-extend-form-fields-in-symfony2.html
to learn how to create the extension.
To have access to session locale, make sure to inject the container. After that you'll be able to get any var value you want.
If the app variable is not available in the form theme it may be a bug. I suggest you create a ticket.
In the meantime you can use the current template as a theme. Something like...
{% form_theme form _self %}
{% block field_label %}
{% set attr = attr|merge({ 'for': id }) %}
{% if required %}
{% set attr = attr|merge({ 'class': attr.class|default('') ~ ' required' }) %}
{% endif %}
<label{% for attrname, attrvalue in attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ label|trans }} ({{ app.session.locale }})</label>
{% endblock %}
If you are using Symfony master (2.1) replace app.session.locale with app.request.locale.