Customization of a form widget in Symfony2/Twig - symfony

In my form template:
{% block field_label %}
{% spaceless %}
<label {{ block('widget_attributes') }}></label>
{% endspaceless %}
{% endblock %}
I need to add some extra class attributes and, of course, display the label (possibly translated). I've found that {{ block('widget_attributes') }} stores a string of attributes of the actual label.
Any chance to get an array type to easily modify it? Where i can find all block names to customize the appearance to fit my needs? Thanks for helping.

Nevermind Notepad++ helped me to find the file:
vendor\symfony\src\Symfony\Bridge\Twig\Resources\views
Three types of label defined:
{# 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 %}>{{ label|trans }}</label>
{% endspaceless %}
{% endblock %}
{% block field_label %}
{% spaceless %}
{% set attr = attr|merge({'for': id}) %}
{{ block('generic_label') }}
{% endspaceless %}
{% endblock field_label %}
{% block form_label %}
{% spaceless %}
{{ block('generic_label') }}
{% endspaceless %}
{% endblock form_label %}

Related

rendering forms and widget in Symfony2

I am developing a website and I would like to personalized how the forms are rendered.
My purpose is for each field I should achieve this structure
<div class="form-group">
<label for=":id">:LABEL</label>
<input type=":type" class="form-control" id=":id" />
</div>
In case of checkbox, the input must to appear first and without class atribute
The options for doing this are listed in Symfony Form Theming documentation.
In your form theme Twig file (normally app/Resources/views/form.html.twig) you should add something like this:
{% block form_row %}
{% spaceless %}
<div class="form-group">
{{ form_label(form) }}
{{ form_errors(form) }} {# Can remove this unless you want inline errors #}
{{ form_widget(form) }}
</div>
{% endspaceless %}
{% endblock form_row %}
{% block form_widget_simple %}
{% spaceless %}
{% set type = type|default('text') %}
{% set attr = attr|merge({'class': (attr.class|default('') ~ ' form-control')|trim}) %}
<input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
{% endspaceless %}
{% endblock form_widget_simple %}
The Ryan answer has needed to add one more line like this:
{% form_theme form _self %}
{% block form_row %}
{% spaceless %}
<div class="form-group">
{{ form_label(form) }}
{{ form_errors(form) }} {# Can remove this unless you want inline errors #}
{{ form_widget(form) }}
</div>
{% endspaceless %}
{% endblock form_row %}
{% block form_widget_simple %}
{% spaceless %}
{% set type = type|default('text') %}
{% set attr = attr|merge({'class': (attr.class|default('') ~ ' form-control')|trim}) %}
<input type="{{ type }}" {{ block('widget_attributes') }} {% if value is not empty %}value="{{ value }}" {% endif %}/>
{% endspaceless %}
{% endblock form_widget_simple %}
as per symfony2 documentation How to customize Form Rendering the current template in which u want to make change , u will have to write the line
{% form_theme form _self %}
in the starting of any block overriding ..

How to show label for overrided checkbox in Symfony Twig

I've overrided the Twig template for my forms in my symfony application so that I could have more control over the labels for checkboxes.
However, I am having problems with the checkbox label.
Here is the code I overrided in my custom template file:
{# Labels #}
{% block form_label %}
{% spaceless %}
{% 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 %}
{% endif %}
{% if 'checkbox' not in block_prefixes %}
<label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{{ label|trans({}, translation_domain) }}</label>
{% endif %}
{% endspaceless %}
{% endblock form_label %}
{# Checkboxes #}
{% block button_label %}{% endblock %}
{% block checkbox_widget %}
{% spaceless %}
<label for="{{ id }}">
<input type="checkbox" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} />
{{ label }}</label>
{% endspaceless %}
{% endblock checkbox_widget %}
It works fine but I can't get the label text node for checkboxes working.
When I have a checkbox it generates something like:
<label><input type="checkbox"/></label>
Where it should be:
<label><input type="checkbox"/>Label Here</label>
Any clue on how to make the label string apear after the checkbox?
Edit:
I came to a solution, that worked pretty fine, but I am not sure if it the best.
{% block form_row %}
{% spaceless %}
<div>
{{ form_errors(form) }}
{% if 'checkbox' in block_prefixes %}
{{ form_widget(form) }}
{{ form_label(form) }}
{% elseif 'radio' in block_prefixes %}
{{ form_widget(form) }}
{{ form_label(form) }}
{% else %}
{{ form_label(form) }}
{{ form_widget(form) }}
{% endif %}
</div>
{% endspaceless %}
{% endblock form_row %}
You can remove the label in {% block choice_widget %} to prevent it from appearing in the default spot.
{% block choice_widget %}
{% spaceless %}
{% if expanded %}
<div {{ block('widget_container_attributes') }}>
{% for child in form %}
{{ form_widget(child) }}
{{ form_label(child) }} {# HERE #}
{% endfor %}
</div>
{% else %}
//....
{% endspaceless %}
{% endblock choice_widget %}
If you do so, you would have to override the {% block radio_widget %} too. Otherwise it won't have a label.
<label for="{{ id }}"><input type="radio" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} />{{ label|trans }}</label>
You can then remove the {% if 'checkbox' not in block_prefixes %} line you put in {% block form_label %}.
It worked for me.
Symfony2 - How to put label and input for checkboxes/radios in a same line?
Edit :
it seems that they split the {% block choice_widget %} in 2.3.3. You have to edit the choice_expanded block now, and remove the label line as above.
{% block choice_widget_expanded %}
{% spaceless %}
<div {{ block('widget_container_attributes') }}>
{% for child in form %}
{{ form_widget(child) }}
{{ form_label(child) }} {# There #}
{% endfor %}
</div>
{% endspaceless %}
{% endblock choice_widget_expanded %}

What is the difference between widget_attributes and widget_container_attributes?

Ok, bad question since semantically I think I can gather the difference by the block names themselves. My real question is how can I control which attributes appear a container and an element when widget_attributes and widget_containter_attributes are required on a given element.
Consider the following:
<div class="ui-select foo bar baz">
<select id="abc_hello_worldtype_name" name="abc_hello_worldtype[name]" class="thud grunt">
...
</select>
</div>
Main things I'm going after are having to set class names on both the div and the select. This is required for both style reasons as well as behavior-related requirements.
The main thing that is confusing me is that both the original widget_attributes and widget_container_attributes both use the attr variable passed in. Are these not intended to be used together?
I found myself doing something like the following today; just making my own blocks copied from the originals and adding to the conditionals. This all seems way too complicated. I know I'm doing it wrong.
{% block choice_widget_collapsed %}
{% spaceless %}
{% set attr = attr|merge({'class': (attr.class|default('') ~ ' ui-select')|trim}) %}
<div {{ block('ui_select_container_attributes') }}>
<select {{ block('ui_select_widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}>
{% if empty_value is not none %}
<option value=""{% if required %} disabled="disabled"{% if value is empty %} selected="selected"{% endif %}{% endif %}>{{ empty_value|trans({}, translation_domain) }}</option>
{% endif %}
{% if preferred_choices|length > 0 %}
{% set options = preferred_choices %}
{{ block('choice_widget_options') }}
{% if choices|length > 0 and separator is not none %}
<option disabled="disabled">{{ separator }}</option>
{% endif %}
{% endif %}
{% set options = choices %}
{{ block('choice_widget_options') }}
</select>
</div>
{% endspaceless %}
{% endblock choice_widget_collapsed %}
Notice the ui_* block references on the div and the select. Those blocks look like:
{% block ui_select_widget_attributes %}
{% spaceless %}
id="{{ id }}" name="{{ full_name }}"{% if read_only %} readonly="readonly"{% endif %}{% if disabled %} disabled="disabled"{% endif %}{% if required %} required="required"{% endif %}{% if max_length %} maxlength="{{ max_length }}"{% endif %}{% if pattern %} pattern="{{ pattern }}"{% endif %}
{% for attrname, attrvalue in attr %}{% if attrname in ['placeholder', 'title'] %}{{ attrname }}="{{ attrvalue|trans({}, translation_domain) }}" {% elseif attrname == 'class' %} class="foopa {{ attrvalue|replace({'ui-select':''}) }}" {% else %}{{ attrname }}="{{ attrvalue }}" {% endif %}
{% endfor %}
{% endspaceless %}
{% endblock ui_select_widget_attributes %}
{% block ui_select_container_attributes %}
{% spaceless %}
{% if id is not empty %}id="{{ id }}" {% endif %}
{% for attrname, attrvalue in attr %}{{ attrname }}="{{ attrvalue }}" {% endfor %}
{% endspaceless %}
{% endblock ui_select_container_attributes %}
When a form field is rendered as single form input (text input, select, checkbox...), widget_attributes is used. When it is rendered as a collection of inputs (form, multiple checkboxes, multiple inputs, ...), widget_container_attributes is used for the container surrounding the inputs (a div, mostly). So no, they are not intended to be used at the same time.
The difference between the two blocks is that widget_attributes renders form-specific attributes ("value", "name"...) while widget_container_attributes renders only generic HTML attributes.
If you want to add additional markup beyond the possibilities of the "attr" option, your best bet is to copy the corresponding block from the form theme (e.g. "choice_widget_collapsed"), paste it into your template, rename the block to match your element's ID with a leading underscore ("_") and a "widget" suffix (e.g. if your element's ID is "form_my_element", the block would be called "_form_my_element_widget") and modify the markup in your template.
{% block body %}
...
{{ form(form) }}
...
{% endblock %}
{% block _form_my_element_widget %}
... modified version of the "choice_widget_collapsed" markup ...
{% endblock %}

How to check if widget is a checkbox in twig

Im theming my forms i want dont show the label if the field is a checkbox
{% form_theme form with _self %}
{% block form_row %}
{% spaceless %}
<div class="mygroup">
{{form_label(form)}} # hide if checkbox
{{form_errors(form)}}
{{form_widget(form)}}
</div>
{% endspaceless %}
{% endblock %}
after a while i found solution in Google Group
{% block form_row %}
{% spaceless %}
<div class="mygroup">
{% if 'checkbox' not in form.vars.block_prefixes %}
{{form_label(form)}}
{% endif %}
{{form_errors(form)}}
{{form_widget(form)}}
</div>
{% endspaceless %}
{% endblock %}

Symony2 Form Templating Error - Variable "widget" does not exist

I am trying to alter the date_widget using symfony2 and twig. I would like to display just the year.
After reading Symfony 2 date input with only year selector and the symfony2 book chapter on templating forms I have copied the date_widget block into my template and am receiving the error:
Variable "widget" does not exist in bundle....
here is the code from my template:
{% extends '::base.html.twig' %}
{% block body %}
{% block date_widget %}
{% spaceless %}
{% if widget == 'single_text' %}
{{ block('field_widget') }}
{% else %}
<div {{ block('widget_container_attributes') }}>
{{ date_pattern|replace({
'{{ year }}': form_widget(form.year),
})|raw }}
</div>
{% endif %}
{% endspaceless %}
{% endblock date_widget %}
....print form (generated though app/console generate:crud)
{% endblock %}
Any Thoughts? Thanks!
put the date_widget block outside of the body block, and add the following code after the initial extends
{% form_theme form _self %}
now, your code should look like this
{% extends '::base.html.twig' %}
{% form_theme form _self %}
{% block body %}
....print form (generated though app/console generate:crud)
{% endblock %}
{% block date_widget %}
{% spaceless %}
{% if widget == 'single_text' %}
{{ block('field_widget') }}
{% else %}
<div {{ block('widget_container_attributes') }}>
{{ date_pattern|replace({
'{{ year }}': form_widget(form.year),
})|raw }}
</div>
{% endif %}
{% endspaceless %}
{% endblock date_widget %}
http://symfony.com/doc/current/book/forms.html#form-theming

Resources