Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony2 - How to put label and input for checkboxes/radios in a same line?

Tags:

php

twig

symfony

In my form I have some checkboxes, but by default, I have :

  • the first radio widget
  • the first label
  • the second radio widget
  • the label

Here is the html code generated by SYmfony2 :

  <div>
    <input ...>
    <label ...></label>
    <input ...>
    <label ...></label>
  </div>

What I want is to have :

the first radio widget the first label
the second radio widget the second label

The html code would be :

  <label .....><input ....></label>

I think I have to override the choice_widget but don't know how to put input and label on the same line

Here is the choice_widget I may need to override :

    {% block choice_widget %}
        {% spaceless %}
            {% if expanded %}
                <div {{ block('widget_container_attributes') }}>
                   {% for child in form %}
                      {{ form_widget(child) }}  {{ form_label(child) }}
                   {% endfor %}
                </div>
            {% else %}
                <select {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}>
                {% if empty_value is not none %}
                     <option value="">{{ empty_value|trans }}</option>
                {% endif %}
                {% if preferred_choices|length > 0 %}
                    {% set options = preferred_choices %}
                    {{ block('widget_choice_options') }}
                        {% if choices|length > 0 and separator is not none %}
                            <option disabled="disabled">{{ separator }}</option>
                       {% endif %}
                {% endif %}
                {% set options = choices %}
                {{ block('widget_choice_options') }}
                </select>
           {% endif %}
      {% endspaceless %}
   {% endblock choice_widget %}
like image 786
Reveclair Avatar asked Jul 16 '12 15:07

Reveclair


4 Answers

I had the same problem, and I was unable to find a solution so I worked it out on my own. You are correct that you do need to override the {% block choice_widget %} block. The first step is to remove the {{ form_label(child) }} line from the {% if expanded %} section that prints out a separate label.

{% block choice_widget %}
{% spaceless %}
    {% if expanded %}
        <div {{ block('widget_container_attributes') }}>
        {% for child in form %}
            {{ form_widget(child) }}
        {#  {{ form_label(child) }} <--------------------- remove this line #}  
        {% endfor %}
        </div>
    {% else %}
    <select {{ block('widget_attributes') }}{% if multiple %} multiple="multiple"{% endif %}>
        {% if empty_value is not none %}
            <option value="">{{ empty_value|trans }}</option>
        {% endif %}
        {% if preferred_choices|length > 0 %}
            {% set options = preferred_choices %}
            {{ block('widget_choice_options') }}
            {% if choices|length > 0 and separator is not none %}
                <option disabled="disabled">{{ separator }}</option>
            {% endif %}
        {% endif %}
        {% set options = choices %}
        {{ block('widget_choice_options') }}
    </select>
    {% endif %}
{% endspaceless %}
{% endblock choice_widget %}

Now you will just need to handle printing the label in the {% block checkbox_widget %} block.

{% 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 }}</label>
{% endspaceless %}
{% endblock checkbox_widget %}

You will need to do the same for {% block radio_widget %} since it would not otherwise have a label now.

{% block radio_widget %}
{% spaceless %}
    <label  for="{{ id }}"><input type="radio" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} />{{ label|trans }}</label>
{% endspaceless %}
{% endblock radio_widget %}
like image 193
Bob F. Avatar answered Nov 11 '22 03:11

Bob F.


With help from Alberto Gaona and James, Symfony 2.4 correct solution to integrate BS3 radio AND checkboxes is as follow :

In your view you have :

{% form_theme form 'AcmeDemoBundle:Form:fields.html.twig' %}

// A radio or checkbox input
{{ form_widget(form.example) }}

Then in your fields.html.twig (which overrides https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig ; see http://symfony.com/doc/current/cookbook/form/form_customization.html)

{# src/Acme/DemoBundle/Resources/views/Form/fields.html.twig #}

{% block choice_widget_expanded %}
{% spaceless %}
    <div {{ block('widget_container_attributes') }}>
    {% for child in form %}
        {% if multiple %}
            <div class="checkbox">
        {% else %}
            <div class="radio">
        {% endif %}

        {{ form_widget(child) }}
        </div>
    {% endfor %}
    </div>
{% endspaceless %}
{% endblock choice_widget_expanded %}

{% block checkbox_widget %}
{% spaceless %}
{% if label is empty %}
    {% set label = name|humanize %}
{% endif %}
    <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 %}

{% block radio_widget %}
{% spaceless %}
{% if label is empty %}
    {% set label = name|humanize %}
{% endif %}
    <label  for="{{ id }}">
        <input type="radio" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} />{{ label|trans({}, translation_domain) }}
    </label>
{% endspaceless %}
{% endblock radio_widget %}
like image 36
Xavier13 Avatar answered Nov 11 '22 04:11

Xavier13


NOTE: Updated Bob F solution for Symfony 2.3 (see https://github.com/symfony/symfony/blob/2.3/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig):

Override choice_widget_expanded:

{% block choice_widget_expanded %}
{% spaceless %}
    <div {{ block('widget_container_attributes') }}>
    {% for child in form %}
        {{ form_widget(child) }}
    {% endfor %}
    </div>
{% endspaceless %}
{% endblock choice_widget_expanded %}

Override checkbox (bootstrap style):

{% block checkbox_widget %}
{% spaceless %}
    <label  for="{{ id }}" class="checkbox {% if checked %}checked{% endif %}" ><span class="icons"><span class="first-icon fui-checkbox-unchecked"></span><span class="second-icon fui-checkbox-checked"></span></span><input type="checkbox" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} />{{ label|trans }}</label>
{% endspaceless %}
{% endblock checkbox_widget %}

Override radiobutton

{% block radio_widget %}
{% spaceless %}
    <label  for="{{ id }}"><input type="radio" {{ block('widget_attributes') }}{% if value is defined %} value="{{ value }}"{% endif %}{% if checked %} checked="checked"{% endif %} />{{ label|trans }}</label>
{% endspaceless %}
{% endblock radio_widget %}
like image 11
Alberto Gaona Avatar answered Nov 11 '22 03:11

Alberto Gaona


When a label is rendered it will include a for attribute - this links the label to the input - see the docs on label here changing the output to what you suggested is just another way of linking the label and the input

If you want the label to display to the left of the input you need to change your template to :

{% for child in form %}
   <div>
      {{ form_label(child) }}  {{ form_widget(child) }} 
   </div>
{% endfor %}

Which renders the label before the input and then this creates the following output

<div>
  <div>
    <label ...></label>
    <input ...>
  </div>
  <div>
    <label ...></label>
    <input ...>
  </div>
</div>

You can then apply some CSS styling to make it display inline :

​div label {
    display: inline-block;
    width: 200px;
}​

By default - without any CSS the label would line up before the input with this HTML layout - but the inline-block allows you to also use the width attribute to ensure all fields are lined up correctly - irrespective of the length of label text

Working example here

like image 2
Manse Avatar answered Nov 11 '22 04:11

Manse