Gilberto Albino
Gilberto Albino

Reputation: 2745

How to override a checkbox in Symfony's Twig Form template

I am currently trying to override the default rendering of checkbox blocks in Symfony 2, but I can't achieve the desired result.

I have created an Doctrine Entity called "Categories", and all the views were properly created.

But the default checkboxes labels in Twig form are not in the correct positioning.

PS.: I removed the attributes from the elements here to make it more clean to read.

As is:

<label>Field</label>
<input type="checkbox" />

Should be:

<label><input type="checkbox" />Field</label>

I've created a template for overriding the block itself:

{% 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|trans({}, translation_domain) }}</label>
{% endspaceless %}
{% endblock checkbox_widget %}

And called it in my edit.html.twig file:

{% extends '::base.html.twig' %}
{% form_theme edit_form 'AppGallerySiteBundle:Form:fields.html.twig' %}

Inside the form I placed the lines:

{{ form_errors(edit_form) }}
{{ form_row(edit_form) }}
{{ form_widget(edit_form) }}
{{ form_rest(edit_form) }}

This works and the checkboxes are overrided, BUT the ordinary label from default twig form template continues being displayed and my overrided checkbox doesn't show the label inside it resulting in:

<label>Field</label>
<label><input type="checkbox" /></label>

Where it should be:

<label><input type="checkbox" />Field</label>

Hope somebody could help. Thanks in advance.

Upvotes: 5

Views: 14541

Answers (3)

joshudev
joshudev

Reputation: 156

In order to correct the order of input and label, you can override the form_row block:

{% block form_row %}
  {% spaceless %}
    {% if 'checkbox' in block_prefixes %}
      {{ form_widget(form) }}
      {{ form_label(form) }}
    {% else %}
      {{ form_label(form) }}
      {{ form_widget(form) }}
    {% endif %}
    {{ form_errors(form) }}
  {% endspaceless %}
{% endblock form_row %}

Upvotes: 2

Marcos
Marcos

Reputation: 4930

The same issue was plaguing our project.

A single Entity field of type PHP Array (so ORM stores it in the database record cell as a JSON string, transparently auto decoding and encoding it) is supposed to break down a list of boolean preferences for the user, each rendered as a checkbox.

So in the EntityType.php, inside the

 public function buildForm(FormBuilderInterface $builder, array $options) 

$builder
 ->add('prefs','collection', 

Then, in the main twig template, instead of {{ form(form) }} it's iterated by row:

{% for j,child in form %}
   <div id="form-child-{{ j }}" title="form-child-{{ j }}; loop={{loop.index}}">
        {{ form_row(child) }} 
   </div>
{% endfor %}     

Though that might not be necessary here.

Higher up in that file, I override the rendering of the form with a theme:

 {% form_theme form 'SystemExtMainBundle:Blocks:checkbox.html.twig' %} 

Which contains:

{% block form_row %}
        {% if form.vars.block_prefixes.1 == 'checkbox'   %}
<div class="col-xs-12 checkbox-margins checkbox-label-padding">
    <div class="errors-container">
    {{ form_errors(form)}}
    </div>  
     {{ form_widget(form,{'attr': {'class': '  form-checkbox-widget'}}) }}{{ form_label(form) }}


</div>


        {% elseif form.vars.block_prefixes.1 == 'choice' %}
<div class="col-xs-12 top-form-title">
                        {{ form_label(form) }}
</div>
<div class="col-xs-12 select-margins">
    <div class="errors-container">
    {{ form_errors(form)}}
    </div>  
                    {{ form_widget(form,{'attr': {'class': 'select-style form-control'}}) }}

</div>
        {% elseif form.vars.block_prefixes.1 == 'submit'%}
         {{ form_widget(form,{'attr': {'class': 'top-form-button form-control pull-rigth'}}) }}
        {% elseif form.vars.block_prefixes.1 == 'text'%}

<div class="col-xs-12 top-form-title">
                        {{ form_label(form) }}
</div>
<div class="col-xs-12 ">
    <div class="errors-container">
    {{ form_errors(form)}}
    </div>  

{% set attr = attr|merge({'class': (attr.class|default('') ~ ' form-control top-form-input')|trim}) %} {{ form_widget(form,{'attr':attr}) }}

</div>
{% else %}

<div class="col-xs-12 top-form-title "> 
                        {{ form_label(form) }}
</div>
<div class="col-xs-12 ">
    <div class="errors-container">
    {{ form_errors(form)}}
    </div>  
                        {{ form_widget(form) }}
</div>
        {% endif %}


{% endblock form_row %}

The essential part was line #7 above: {{ form_widget(form,{'attr': {'class': ' form-checkbox-widget'}}) }}{{ form_label(form) }} for checkboxes, which reverses the widget and label order into what I wanted (putting the interactive checkbox first, before its text label).

Upvotes: -1

You should disable rendering label for checkboxes. So you need to override block form_label like this:

{% block form_label %}
{% if 'checkbox' not in block_prefixes %}
  {{ parent() }}
{% endif %}
{% endblock form_label %}

Upvotes: 5

Related Questions