简体   繁体   中英

Date picker with Twig and Javascript

This is my current code in Twig for datepicker (it's only static, not dynamic, not yet linked with Form Type)

<div class="form-group">
    <label>Date of Birth</label>
    <select id="year"></select>
    <select id="month"></select>
    <select id="day"></select>
</div>

Below is JavaScript code

<script src="{{ asset('bundles/hearwegohearwego/js/homepage/select-birthday.js') }}"></script>
    <script type="text/javascript">
        var today= new Date();
        var yy= today.getFullYear();
        var dd=today.getDate();
        var mm=today.getMonth()+1;
        selectBirthday("#year", "#month", "#day", {
            year : 1938,
            month : mm,
            day : dd,
            yearRange : 75,
            endYear : yy
        });
    </script>

In select-birthday.js

function selectBirthday(yearSelector, monthSelector, daySelector, config) {
    if (config == undefined) {
        config = {};
    }

    if (config.year == undefined) {
        config.year = new Date().getFullYear();
    }

    if (config.month == undefined) {
        config.day = new Date().getMonth() + 1;
    }

    if (config.month == undefined) {
        config.day = new Date().getDate();
    }

    if (config.yearRange == undefined) {
        config.yearRange = 100;
    }

    if (config.endYear == undefined) {
        config.endYear = new Date().getFullYear();
    }

    var birthdayYear = $(yearSelector);
    if (birthdayYear.length == 0) {
        throw "can not find 'year' select control";
    }
    for (var y = config.endYear; y > config.endYear - config.yearRange; y--) {
        if (y == config.year) {
            $('<option value="' + y + '" selected="selected">' + y + '</option>').appendTo(birthdayYear);
        } else {
            $('<option value="' + y + '" >' + y + '</option>').appendTo(birthdayYear);
        }
    }

    var birthdayMonth = $(monthSelector);
    if (birthdayMonth.length == 0) {
        throw "can not find 'month' select control";
    }
    for (var m = 1; m <= 12; m++) {
        if (m == config.month) {
            $('<option value="' + m + '" selected="selected">' + m + '</option>').appendTo(birthdayMonth);
        } else {
            $('<option value="' + m + '">' + m + '</option>').appendTo(birthdayMonth);
        }
    }

    var birthdayDay = $(daySelector);
    if (birthdayDay.length == 0) {
        throw "can not find 'day' select control";
    }
    for (var d = 1; d <= 31; d++) {
        if (d == config.day) {
            $('<option value="' + d + '" selected="selected">' + d + '</option>').appendTo(birthdayDay);
        } else {
            $('<option value="' + d + '">' + d + '</option>').appendTo(birthdayDay);
        }
    }

    birthdayYear.change(onBirthdayChanged);
    birthdayMonth.change(onBirthdayChanged);
    birthdayDay.change(onBirthdayChanged);

    var day29 = birthdayDay.find('option[value="29"]');
    var day30 = birthdayDay.find('option[value="30"]');
    var day31 = birthdayDay.find('option[value="31"]');

    function onBirthdayChanged() {
        var year = parseInt(birthdayYear.val());
        var month = parseInt(birthdayMonth.val());
        var day = parseInt(birthdayDay.val());

        switch (month) {
            case 4:
            case 6:
            case 9:
            case 11:
                if (day > 30) {
                    birthdayDay.val(30);
                }
                day29.show();
                day30.show();
                day31.hide();
                break;
            case 2:
                if (!isLeapYear(year)) {
                    if (day > 28) {
                        birthdayDay.val(28);
                    }
                    day29.hide();
                } else {
                    if (day > 29) {
                        birthdayDay.val(29);
                    }
                    day29.show();
                }
                day30.hide();
                day31.hide();
                break;
            default:
                day29.show();
                day30.show();
                day31.show();
                break;
        }
    }

    function isLeapYear(year) {
        return 0 == year % 4 && (year % 100 != 0 || year % 400 == 0);
    }
}

The JavaScript code is to create 3 select tags to choose day, month, year so that they follows natural rules (28 days of February, leap year...)

If I create Form Type like this ( UserRegisterType.php )

<?php

namespace HearWeGo\HearWeGoBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class UserRegisterType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('email', 'text')
                ->add('firstName', 'text')
                ->add('lastName', 'text')
                ->add('dateOfBirth', 'date', array(
                    'years' => range(date('Y') -100, date('Y')-5)
                ))
                ->add('phone', 'text')
                ->add('password', 'password')
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'HearWeGo\\HearWeGoBundle\\Entity\\User'
        ));
    }

    public function getName()
    {
        return 'user_register_type';
    }
}

Only one field - dateOfBirth of date type - is created, and it doesn't follow natural rules I want. How can I inject a datepicker to my aforementioned frontend and JavaScript code?

A very simple solution is to create your own formtype element, you can call it datepicker for instance.

// YourBundle/Resources/views/Form/fields.html.twig
{% block datepicker_widget %}
    <input type="date" {% if value is not empty %}value="{{ value }}" {% endif %} {{ block('widget_attributes') }}/>
{% endblock %}

Then at top of your twig call this file

// Top of yourTwigFile.html.twig
{% form_theme form 'YourAppYourBundle:Form:fields.html.twig' %}

Last step is to change the type of element used

// HearWeGo/HearWeGoBundle/Form/UserRegisterType.php
[...]
->add('dateOfBirth', 'datepicker', array(
    'years' => range(date('Y') -100, date('Y')-5)
))
[...]

This way you will absolutly not need any complicated Javascript, just use the default render behaviour of the web browser (with <input type="date" /> )

If you are using Twitter Bootstrap, you can use this twig template instead of the first I gave in order to have a prettier rendering

{# DATEPICKER #}

{% block datepicker_widget %}
    <input placeholder="Date" class="form-control datepicker" type="text" {% if value is not empty %}value="{{ value }}" {% endif %} {{ block('widget_attributes') }}/>
{% endblock %}

{# DATETIMEPICKER #}

{% block datetimepicker_widget %}
    {{ form_errors(form.date) }}
    {{ form_errors(form.time) }}
    <div class="input-group datetimepicker">
        <span class="input-group-addon">Le</span>
        {{ form_widget(form.date) }}
        <span class="input-group-addon inner-addon">à</span>
        {{ form_widget(form.time) }}
    </div>
{% endblock %}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM