Introduction

In a form I’ve recently worked on using Symfony, I had to show a group of selectable checkboxes. In this case, the user can select any number of checkboxes an also in one group, two of the checkboxes I needed to use Javascript to detect when the box was selected. I wrote about that in my Javascript Code Refactoring article.

There are two types of problems when using a ChoiceType built-in Field Type set to element type of checkboxes in Symfony:

  1. Rending in Twig is not easy.
  2. Setting attributes is not easy, and may not work as you expect.

The above two reasons are why I decided to write this article.

Example Code

Below is an example checkbox group that I created in a form class for some employment questions that are asked in a form:

public function buildForm(FormBuilderInterface $builder, array $options)
{
   $builder
      ...
      // Employment
     ->add('employ', ChoiceType::class, array(
           'mapped' => false,
           'required' => false,
           'expanded' => true,
           'multiple' => true,
           'label' => 'Employment',
           'choices' => array(
                   'I have a job. # of hours/week:' => 'have_job',
                   'I am work study eligible' => 'work_study',
                   'I need assistance in finding a job' => 'find_work',
                   'I need to learn interviewing skills' => 'interview',
                   'I have no employment needs at this time' => 'no_needs',
                   'I volunteer for a non-profit organization' => 'non_profit',
                   'I need assistance with my resume' => 'resume',
                   'I need assistance finding an internship' => 'intern',
                   'I am undecided about my career or major' => 'major',
                   'Other:' => 'other',
            ),
      ))
      ...
}

Then when I tried to render in a single html table row in Twig, using code like this:

<tr><td>{{ form_widget(form.employ) }}</td></tr>

Then this appears like this rendering in a web page:

TwigRender

Notice the problem in that each checkbox appears inline directly after each other. I tried to use the Twig nl2br filter together with “\n” in my choice values, but that didn’t work since I really need another table row to show each of the checkboxes and labels.

Adding Checkboxes to TR

Since a ChoiceType in a Symfony form is an array of checkboxes, then we can use a Twig for loop to properly show the widget and label in a HTML table row. The Twig code needed is as follows:

{% for i in 1..8 %}
   <tr><td>&emsp;{{ form_widget(form.employ[i]) }}{{ form_label(form.employ[i]) }}</td></tr>
{% endfor %}

The unfortunate part of the above code is, in order to add an attribute like a Javascript onchange, this has do be done in Twig on the particular element like so:

<tr><td>&emsp;{{ form_widget(form.employ[0],{'attr':{'onchange':'changeJobHours()'}}) }}
   {{ form_label(form.employ[0]) }}&emsp;
   {{ form_label(form.job_hours) }}{{ form_widget(form.job_hours) }}</td></tr>

The above adds an onchange attribute for the first checkbox. I also have a job hours and label, but those are hidden and shown when a onchange event is triggered and box is selected.

Resultant Code

The overall resultant code looks like the following:

<table id='6th' style='border: 1px solid; margin-left: auto; margin-right: auto; width: 50%; display: none;'
   background="{{ asset('images/indneeds_assess/employment2.png') }}">
   <tr><td colspan="2"><b>{{ form_label(form.employ) }}</b></td></tr>
   <tr><td>{{ form_widget(form.employ) }}</td></tr>
   <tr><td>&emsp;{{ form_widget(form.employ[0],{'attr':{'onchange':'changeJobHours()'}}) }}
      {{ form_label(form.employ[0]) }}&emsp;
      {{ form_label(form.job_hours) }}{{ form_widget(form.job_hours) }}</td></tr>
   {% for i in 1..8 %}
      <tr><td>&emsp;{{ form_widget(form.employ[i]) }}{{ form_label(form.employ[i]) }}</td></tr>
   {% endfor %}
   <tr><td>&emsp;{{ form_widget(form.employ[9],{'attr':{'onchange':'changeEmploy()'}}) }}
      {{ form_label(form.employ[9]) }}&emsp;
      {{ form_label(form.employ_other) }}{{ form_widget(form.employ_other) }}</td></tr>
</table>

The above code puts each checkbox in on HTML tr elements. The resultant web page looks like the following and appears much better than the original.

Employment

Advertisements