Bootstrap 3: отформатированные флажки с Symfony & Twig

Как создать отформатированную группу флажков, как описано в документации Bootstrap, используя форму Symfony Form Factory и Twig?

Используя что-то вроде

<div class="row">
  <div class="col-lg-4">
    {{ form_label(form.sample) }}
  </div>
  <div class="col-lg-8">
    {{ form_widget(form.sample) }}
  </div>
</div>

не приведет к необходимости вывода:

a) каждый флажок в структуре Bootstrap 3, например:

<div class="radio">
  <label>
    <input type="radio" ... />Option one
  </label>
</div>

b), кроме того, возможность выводить флажки в двух или более столбцах при необходимости:

<div class="row">
  <div class="col-lg-6 col-md-6">
    <div class="radio"> ... </div>
  </div>
  <div class="col-lg-6 col-md-6">
    <div class="radio"> ... </div>
  </div>
</div>

Ответ 1

Правильный способ сделать это - создать свою собственную тему формы. Здесь я не буду писать все, но для вас важно то, что:

{% block choice_widget_expanded %}
{% spaceless %}
    <div {{ block('widget_container_attributes') }} class="my-form-choices">
    {% for child in form %}
        {{ form_widget(child) }}
    {% endfor %}
    </div>
{% endspaceless %}
{% endblock choice_widget_expanded %}

{% block checkbox_widget %}
{% spaceless %}
    <div class="checkbox">
        <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>
    </div>
{% endspaceless %}
{% endblock checkbox_widget %}

Я удалил рендеринг меток из choice_widget_expanded, чтобы я мог установить флажок внутри тега метки, точно так же, как то, что у вас есть в вашем решении. Но вы можете в принципе делать все, что хотите, в своей форме. Вы также можете перезаписать radio_widget, если хотите.

Если вы внимательно посмотрите на div вокруг флажков, я дал ему класс "my-form-choices". Вы можете дать ему классы, которые вы хотите. Это может быть "col-lg-8", как и у вас, но для меня имеет смысл иметь общее имя класса, а затем использовать mixins в вашем файле меньше. Ваш меньше файлов будет выглядеть так:

@import '../../../../../../vendor/twitter/bootstrap/less/bootstrap.less';

.my-form-row {
    .make-row();
}

.my-form-choices {
    .make-lg-column(8);
}

.my-form-row-label {
    .make-lg-column(4);
}

Но это до вас. Вам не нужно это делать, если вы этого не хотите. Наконец, вы используете свою тему, запустив ветку для своей страницы следующим образом:

{% extends 'MyOwnBundle::layout.html.twig' %}
{% form_theme form 'MyOwnBundle:Component:formtype.html.twig' %}

И вы показываете строку просто так (поле, которое я использовал в моем тесте, - это доступность, твой образец):

{{ form_row(form.availability) }}

Я пробовал это (с Symfony 2.4), и он работает. Результат выглядит примерно так:

<div class="my-form-row">
    <div class="my-form-row-label">
        <label class="required">Availability</label>
    </div>
    <div class="my-form-choices" id="myown_website_contactmessage_availability">
        <div class="checkbox">
            <label for="myown_website_contactmessage_availability_0">
                <input type="checkbox" value="morning" name="myown_website_contactmessage[availability][]" id="myown_website_contactmessage_availability_0">
                Morning
            </label>
        </div>
        <div class="checkbox">
            <label for="myown_website_contactmessage_availability_1">
                <input type="checkbox" value="afternoon" name="myown_website_contactmessage[availability][]" id="myown_website_contactmessage_availability_1">
                Afternoon
            </label>
        </div>
        <div class="checkbox">
            <label for="myown_website_contactmessage_availability_2">
                <input type="checkbox" value="evening" name="myown_website_contactmessage[availability][]" id="myown_website_contactmessage_availability_2">
                Evening
            </label>
        </div>
    </div>
</div>

Также обратите внимание, что у меня нет подстрок, как у вас в вашем решении. На самом деле, ваше решение выходит за рамки вопроса, который вы задавали в первую очередь.

EDIT: здесь решение для наличия нескольких столбцов

Чтобы иметь несколько столбцов, это быстрое решение. Во-первых, тема формы может быть примерно такой:

{% block choice_widget_expanded %}
{% spaceless %}
    <div class="my-form-choices-container">
        <div {{ block('widget_container_attributes') }} class="my-form-choices">
        {% for child in form %}
            {{ form_widget(child) }}
        {% endfor %}
        </div>
    </div>
{% endspaceless %}
{% endblock choice_widget_expanded %}

{% block checkbox_widget %}
{% spaceless %}
    <div class="my-form-choice">
        <div class="checkbox">
            <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>
        </div>
    </div>
{% endspaceless %}
{% endblock checkbox_widget %}

И тогда ваш файл меньше будет выглядеть так:

@import '../../../../../../vendor/twitter/bootstrap/less/bootstrap.less';

.my-form-row {
    .make-row();
}

.my-form-row-label {
    .make-lg-column(4);
}

.my-form-choices-container {
    .make-lg-column(8);
}

.my-form-choices {
    .make-row();
}

.my-form-choice {
    .make-md-column(6);
}

В этом решении вы меняете количество столбцов, изменяя размер столбцов. Ячейки должны аккуратно складываться. В этом случае лучше скомпилировать (я не буду объяснять это здесь). Я пробовал это решение, и он работает хорошо. Преимущество использования меньше в этом случае состоит в том, что вы можете использовать одну и ту же тему формы на нескольких страницах и изменять количество столбцов, просто имея другой "меньший" файл для каждой из ваших страниц.

Ответ 2

Вам нужно получить доступ к формам vars, которые содержат информацию о флажках:

form.sample.vars.form.children

теперь вы можете пропустить флажки и получить доступ к значениям:

{% for children in form.sample.vars.form.children %}
  <div class="checkbox>
    <label>
      <input type="checkbox" name="{{ children.vars.full_name }}" id="{{ children.vars.id }}" value="{{ children.vars.value }}"{% if children.vars.data %} checked="checked"{% endif %} />
      {% if children.vars.label is defined %}
        {{ children.vars.label|trans }}
      {% else %}
        {{ children.vars.value|capitalize|trans }}
      {% endif %}
    </label>
  </div>
{% endfor %}

Я помещаю этот код в шаблон Twig и добавляю некоторую логику для создания строк с переменными столбцами, поэтому он выглядит так:

{% set cols = columns|default(1) %}
{% set i = 1 %}
{% for children in childrens %}
  {% if i == 1 %}<div class="row">{% endif %}
  <div class="col-lg-{{ 12/cols }} col-md-{{ 12/cols }}">
    <div class="checkbox {{ class|default('') }}">
      <label>
        <input type="checkbox" name="{{ children.vars.full_name }}" id="{{ children.vars.id }}" value="{{ children.vars.value }}"{% if children.vars.data %} checked="checked"{% endif %} />
        {% if children.vars.label is defined %}
          {{ children.vars.label|trans }}
        {% else %}
          {{ children.vars.value|capitalize|trans }}
        {% endif %}
      </label>
    </div>
  </div>
  {% set i = i+1 %}
  {% if i > cols %}
    </div>
    {% set i = 1 %}
  {% endif %}
{% endfor %}
{% if i != 1 %}</div>{% endif %}

теперь вы можете включить этот шаблон флажка, где он вам нужен:

<div class="row">
  <div class="col-lg-4">
    {{ form_label(form.sample) }}
  </div>
  <div class="col-lg-8">
    {% include 'checkbox.twig' with {childrens:form.sample.vars.form.children, columns:2} only %}
  </div>
</div>

приведенный выше пример возвращает хорошо отформатированный вывод Bootstrap 3 с флажками в двух столбцах:

<div class="row">
  <div class="col-lg-4">
    <label class="required">Veranstalter</label>
  </div>
  <div class="col-lg-8">
    <div class="row">
  <div class="col-lg-6 col-md-6">
    <div class="checkbox ">
      <label><input type="checkbox" name="form[sample][]" id="form_sample_0" value="DUMMY">Dummy</label>
    </div>
  </div>
  <div class="col-lg-6 col-md-6">
    <div class="checkbox ">
      <label><input type="checkbox" name="form[sample][]" id="form_sample_1" value="DUMMY_1">Dummy 1</label>
    </div>
  </div>
</div>
<div class="row">
  <div class="col-lg-6 col-md-6">
    <div class="checkbox ">
      <label><input type="checkbox" name="form[sample][]" id="form_sample_2" value="DUMMY_2">Dummy 2</label>
    </div>
  </div>
</div>  

Он прост в использовании и также будет работать для переключателей - просто замените класс "checkbox" на "radio".

Ответ 3

В этот вопрос встал вопрос и решил поделиться своим решением. У меня уже был файл переопределения формы, но мне не нравилось то, что я нашел в другом месте. Так написал блок form_label, как это описано.

{% 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 -%}
        {% set label = name|humanize %}
    {%- endif -%}
    <label{% for attrname, attrvalue in label_attr %} {{ attrname }}="{{ attrvalue }}"{% endfor %}>{% if 'checkbox' in block_prefixes %}{{ form_widget(form) }}{% endif %}{{ label|trans({}, translation_domain) }}</label>
{%- endif %}
{%- endblock form_label %}

Затем блок form_row выглядит так:

{% block form_row %}
{% spaceless %}

{% if 'checkbox' not in block_prefixes %}
   <div class="form-group"> 
        {{ form_label(form) }}
        {{ form_errors(form) }}
        {% if 'datetime' not in block_prefixes %}
            {{ form_widget(form, { 'attr': {'class': 'form-control'} }) }}
        {% else %}
            {{ form_widget(form) }}
        {% endif %}
    </div>
{% else %}
    {% import _self as forms %}
    <div class="checkbox">
        {{ form_label(form) }}
    </div>
{% endif %}

{% endspaceless %}
{% endblock %}

Я выбираю этот метод, потому что это позволило мне продолжить использовать базовый метод формы (формы) в шаблонах. Надеюсь, это поможет вам.

Ответ 4

Если вы ищете простую версию этого ответа (т.е. вы уже применили тему bootstrap_3_layout к своей форме и просто хотите применить пользовательский текст ярлыка)

{{ form_widget( form.field, { 'label': 'Custom Label Text' } ) }}