Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to display a month-year dropdown in Symfony2

Tags:

forms

symfony

In my application, the user hsa to give a date by only selecting a month and a year in two dropdown lists. How can I achieve that?

Here is what I've tried so far :

In my Form :

$builder->add('date1', 'date', array(
 'widget'      => 'choice',
 'empty_value' => '',
 'format'      => 'MMMM-yyyy',
 'input'       => 'datetime',
 'years'       => range(date('Y'), date('Y') - 30, -1)
)

which actually works and displays it exactly as I want but when validating the form, I get an error :

This value is not valid

A screenshot of the wanted result :

Screenshot

like image 325
i.am.michiel Avatar asked Apr 12 '12 14:04

i.am.michiel


2 Answers

@Oleg was pretty close to the correct answer. You have to use a view transformer to make sure that the DateTime gets a day.

/* In your formType.php */

$builder->add(
   $builder->create('date1', 'date', array(
       'format'      => 'MMMM-yyyyd', // you need to have 'y', 'M' and 'd' here
       'years'       => range(date('Y'), date('Y') - 30, -1)
   ))
   ->addViewTransformer(new IncompleteDateTransformer()));
)

Create a transformer:

class IncompleteDateTransformer implements DataTransformerInterface
{
/**
 * Do nothing when transforming from norm -> view
 */
public function transform($object)
{
    return $object;
}

/**
 * If some components of the date is missing we'll add those. 
 * This reverse transform will work when month and/or day is missing
 *
 */
public function reverseTransform($date)
{
    if (!is_array($date)) {
        return $date;
    }

    if (empty($date['year'])) {
        return $date;
    }

    if (empty($date['day'])) {
        $date['day']=1;
    }

    if (empty($date['month'])) {
        $date['month']=1;
    }

    return $date;
}
} 

Create a twig template where you use a custom form theme from the file itself:

{# example.html.twig #}
{% form_theme form _self %}

{% block date_widget %}
{% spaceless %}
    {% if widget == 'single_text' %}
        {{ block('field_widget') }}
    {% else %}
        <div {{ block('widget_container_attributes') }}>
            <div class="datetime_widget">
                {{ date_pattern|replace({
                '{{ year }}': form_widget(form.year),
                '{{ month }}': form_widget(form.month),
                '{{ day }}':  '',
                })|raw }}
            </div>
        </div>
    {% endif %}
{% endspaceless %}
{% endblock date_widget %}

<h2>Select a date</h2>
{{ form(form) }}

References:

  • Data transformers
  • Form customization
  • Choice type
like image 134
Tobias Nyholm Avatar answered Oct 15 '22 05:10

Tobias Nyholm


Example for credit card expiration date:

$builder->add('expirationDate', 'date', array(
 'label' => 'Expiration date',
 'widget' => 'choice',
 'empty_value' => array('year' => 'Year', 'month' => 'Month', 'day' => 'Day'),
 'format' => 'dd-MM-yyyy',
 'input' => 'string',
 'data' => date('Y-m-d'),
 'years' => range(date('Y'), date('Y') + 10),
));

Then you must render this field manually.

Your form's twig template:

{{ form_row(form.expirationDate, {'date_pattern': '<span style="display: none;">{{ day }}</span> {{ month }} <span class="delim">&#47;</span> {{ year }}'}) }}

Overriding date_pattern will hide day select. You will get month / year format.

like image 26
Jekis Avatar answered Oct 15 '22 03:10

Jekis