简体   繁体   中英

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.

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 %}

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 %}

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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM