Survey Form in Symfony


Introduction

I’ve recently had to develop a form in a Symfony application that has a section of it with survey type questions. In Symfony it’s not so obvious that the ChoiceType field type is the most suitable type, but it definitely is the one to use. This article describes how to create the survey form.

Original Requirements

I didn’t have any written down requirements other than the existing form, and below is a screenshot of what that looks like:

original_survey

As you can see, it uses checkboxes; which is not appropriate. The reason being is that normally in a group of checkboxes, you can check any or all of them. In a survey, you only want to check one of them. So a radio button is the best choice.

Also look closely at the headings. The problem is the order. The order should be from one extreme to another. So instead this order:

Strongly Agree — Somewhat Agree — Somewhat Disagree — Strongly Disagree.

So my form would need to incorporate those need requirement changes.

ChoiceType in Form Class

In my form class, I initially used the following sample code for the “recommend” set of radio button choices:

->add('sur_recommend', ChoiceType::class, array(
    'mapped' => false,
    'label' => 'I would recommend this program to my friends and '.
               'family as a great opportunity',
    'choices' => array(
            'strong_A' => 'strong_A',
            'some_A' => 'some_A',
            'some_D' => 'some_D',
            'strong_D' => 'strong_D',
    ),
    'expanded' => true,
    'multiple' => false,
))

With the two settings “expanded” set to true and “multiple” set to false, this sets the choice group to radio buttons. The “mapped” set to false just means that “sur_recommended” is not a Doctrine database column, so the data is not mapped. I keep the values and the keys the same, since I don’t want to show any labels in my case.

Unfortunately with the above code, it doesn’t quite work for my case. If I render in Twig using just this code:

{{ form_widget(form.sur_recommend) }}

Then the resultant output will render like the following screenshot:

buttons_w_labels

I don’t want those labels appearing at all, but instead in a column header on the top.

Fixing the Code

In order to prevent the labels from showing, you should set “choice_label” to false, like the following code:

->add('sur_recommend', ChoiceType::class, array(
    'mapped' => false,
    'label' => 'I would recommend this program to my friends and '.
               'family as a great opportunity',
    'choice_label' => false,
    'choices' => array(
            'strong_A' => 'strong_A',
            'some_A' => 'some_A',
            'some_D' => 'some_D',
            'strong_D' => 'strong_D',
    ),
    'expanded' => true,
    'multiple' => false,
))

Then when rendered the labels no longer appear. The other problem is, we have a label for the choice group, but wee just want it to appear on the left side, and the buttons on the right. We also need the buttons to each appear under the names of each of the column headings. This needs to be done in Twig, which is described next.

Using Twig to render Properly

Twig is a powerful rendering language, and it can greatly simply any of your programming efforts. So I highly recommend learning how to use it properly. You can always use Twigfiddle to experiment first with code that you need to write and also to help you learn.

Since I don’t render each of the choice values (which would be labels), I need to put a header column on the top, and put each of the choice group labels on the left. Then each of the radio buttons need to line up under the header columns. To do this, a html table is a good idea.

Here is the Twig code that I came up with:

<fieldset>
<legend>Survey:</legend>
   <table>
      <tr><td></td><td>Strongly Agree</td><td>Somewhat Agree</td>
          <td>Somewhat Disgree</td><td>Strongly Disgree</td></tr>
      <tr style="text-align: center;"><td>{{ form_label(form.sur_recommend) }}</td>
         {% for i in 0..3 %}
            <td>{{ form_widget(form.sur_recommend[i]) }}</td>
         {% endfor %}
      </tr>
      ...

   </table>
</fieldset>

Notice the heading column is in one row, and I have a td element for each heading. I use the form_label to show the choice group label on the left. Notice I have a for loop, and a td element for each radio button as part of the choice group.

The resultant code renders on a page as follows:

final_survey

This is quite functional and looks good and similar to the original.

Advertisements

About Alvin Bunk
Hi, I'm a software developer at Taft College.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: