Buy
Buy
This tutorial has a new version in planning, check it out!

Creating a Date Picker Field

What's the ugliest part of the form? Yeah, we all know. It's this crazy 3 drop-downs used for the date field.

In modern times, if we need a date field, we're going to render it as a text field and use a fancy JavaScript widget to help the user fill it in.

Head back to the list of fields. It doesn't take long to find the one that's being guessed for the "First Discovered At" field: it's DateType.

Let's see if there's a way to render this as a text field instead.

Setting widget to single_text

Check out the widget option:

The basic way in which this field should be rendered.

It can be either choice - the three select fields, which is lame - 3 text fields, or a single text field with single_text. Ah hah!

Back in the form, let's pass in DateType::class even though we could be lazy and pass null. Create the array for the third argument and add widget set to single_text:

... lines 1 - 9
use Symfony\Component\Form\Extension\Core\Type\DateType;
... lines 11 - 13
class GenusFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
... lines 19 - 34
->add('firstDiscoveredAt', DateType::class, [
'widget' => 'single_text'
])
;
}
... lines 40 - 46
}

Check it out.

HTML5 Date Types are Cool(ish)

Boom! It looks great. In fact, check this out: it already has some widget coolness: with a drop-down and a nice calendar.

Tip

If you don't see a fancy widget, don't worry! Not all browsers support this, which is why we'll use a true JavaScript widget soon!

This is not coming from Symfony: it's coming from my browser. Because as soon as we made this a single_text widget, Symfony rendered it as an <input type="date"> HTML5 field. Most browsers see this and add their own little date widget functionality.

Ready for the lame news? Not all browsers do this. And that means that users without this feature will have a pretty tough time trying to figure out what date format to pass.

Adding a JavaScript Date Picker

Instead, let's add a proper JavaScript widget. Google for "Bootstrap Date Picker". Ok, this first result looks pretty awesome - let's go for it!

First, we need to import new CSS and JS files. In new.html.twig, override the block stylesheets from the base layout. Add {% endblock %} and print {{ parent() }}:

... lines 1 - 2
{% block stylesheets %}
{{ parent() }}
... lines 5 - 6
{% endblock %}
... lines 8 - 35

Because I'm lazy, I'll paste the URL to a CDN that hosts this CSS file:

... lines 1 - 2
{% block stylesheets %}
{{ parent() }}
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.6.0/css/bootstrap-datepicker.css">
{% endblock %}
... lines 8 - 35

But, you can download it if you want.

Do the same thing for block javascripts. Add {% endblock %} and call parent():

... lines 1 - 8
{% block javascripts %}
{{ parent() }}
... lines 11 - 18
{% endblock %}
... lines 20 - 35

I've got a CDN URL ready for the JavaScript file too. Go me!

... lines 1 - 8
{% block javascripts %}
{{ parent() }}
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.6.0/js/bootstrap-datepicker.min.js"></script>
... lines 13 - 18
{% endblock %}
... lines 20 - 35

Adding a class Attribute

Next, how do we activate the plugin? According to their docs: it's pretty simple: select the input and call .datepicker() on it.

Personally, whenever I want to target an element in JavaScript, I give that element a class that starts with js- and use that with jQuery.

So the question is, how do we give this text field a class? You can't!

I mean you can! In 2 different ways! The first is by passing another option to the field in the form class. Add an attr option to an array. And give that array a class key set to js-datepicker:

... lines 1 - 13
class GenusFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
... lines 19 - 34
->add('firstDiscoveredAt', DateType::class, [
... line 36
'attr' => ['class' => 'js-datepicker'],
... line 38
])
;
}
... lines 42 - 48
}

Setting up the JavaScript

Next, in our template, add the jQuery(document.ready) block. Hook it up with $('.js-datepicker').datepicker():

... lines 1 - 8
{% block javascripts %}
{{ parent() }}
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.6.0/js/bootstrap-datepicker.min.js"></script>
<script>
jQuery(document).ready(function() {
$('.js-datepicker').datepicker();
});
</script>
{% endblock %}
... lines 20 - 35

Easy. Give it a try.

Scroll down and... hey! There it is! I can see the cool widget. And if I click... um... if I click... then - why is nothing happening?

HTML5 versus DatePicker: Fight!

It turns out, the HTML5 date functionality from my browser is fighting with the date picker. Silly kids. This doesn't happen in all browsers, it's actually something special to Chrome.

To fix this, we need to turn off the HTML5 date functionality. In other words, we want render this as a true <input type="text"> field, not a date field.

To do that, open the form type. There's one last option that will help us: set html5 to false:

... lines 1 - 13
class GenusFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
... lines 19 - 34
->add('firstDiscoveredAt', DateType::class, [
... lines 36 - 37
'html5' => false,
])
;
}
... lines 42 - 48
}

Try it one last time. HTML5 is out of the way and the date picker is in charge.

Pretty awesome.

Leave a comment!

  • 2018-04-04 weaverryan

    Hey Mehdi Marchouk!

    Wow, this is tough question! My immediate reaction is this: timezone. And, unfortunately, I'm far from an expert on timezones. But, if I'm right, then probably you do *not* see this issue if you try this during the middle of the day. Am I right? Anyways, my instinct is that the data is being, for example, submitted UTC, then being converted to some other timezone (probably whatever timezone is in your php.ini). This is definitely weird & ugly, as you're trying to only deal with *dates* not times. You can play with the mode_timezone or view_timezone settings (https://symfony.com/doc/cur... to see if you can fix this. I admit, I have not seen this issue before!

    Cheers!

  • 2018-04-03 Mehdi Marchouk

    Hello ,
    I have a Date Field , I set it like that in a FormType :
    ->add('dateNaissance', DateType::class, array(
    'attr' => array( 'placeholder' => '31/12/1978' ),
    'label' => 'Date de naissance',
    'widget' => 'single_text',
    'html5' => false,
    'format' => 'dd/mm/yyyy'
    ))

    The field in the Entity :
    /**
    * @var \DateTime
    *
    * @ORM\Column(name="date_naissance", type="date", nullable=true)
    */
    private $dateNaissance;

    I am using that js plugin : http://www.daterangepicker.com (daterangepicker) :
    $('input.single-daterange').daterangepicker({ "singleDatePicker": true });

    When I submit the form And see what's happen in the form profiler :

    View Format : 05/31/2018"
    Normalized Format
    DateTime @1515112260 {#1478 ▼
    date: 2018-01-05 00:31:00.0 UTC (+00:00)
    }

    There are two N.B., first Data transformers changes the day from 31 to 01, second it changes the format, Why ? and How to solve it ? Thank you

  • 2017-12-26 Robertino Vasilescu

    Hello Ryan,
    Thank you for replying so quick, especially during Xmas holidays!
    Yep, you're absolutely right, I have chosen the wrong class from the autocomplete list :-(
    Those guys at PhpStorm are to blame, why didn't they made the editor guess the user's mind instead of letting him choose :-)
    And of course I should really understand what the messages are saying, now that the veil lifted off my eyes it is pretty clear.
    As a side note, to me the real challenge (after getting to a normal skill level) seems to be identifying which class to use and where to get it from :-(
    Again, thanks for the help!
    P.S. No guarantee I won't ask a naive question again.

  • 2017-12-26 weaverryan

    Hey Robertino Vasilescu!

    Hmm, let's see if we can debug this nasty issue :). Ah, yep, I see it! It's really subtle! Notice that the error says that it could not load the type "Doctrine\DBAL\Types\DateType". The class you actually want is "Symfony\Component\Form\Extension\Core\Type\DateType". The problem? You probably auto-completed the wrong use statement when you were typing the class. DateType is one of those annoying classes that appears multiple times in multiple libraries. Update the use statement and you should be golden!

    Cheers!

  • 2017-12-25 Robertino Vasilescu

    Hey guys,
    I am watching these tutorials with great interest and pleasure!
    Everything worked allright since the track began but now I have a problem with adding the DateType, the error being:

    Could not load type "Doctrine\DBAL\Types\DateType"

    500 Internal Server Error - InvalidArgumentException

    I have checked and everything seems exactly like in your tut, the declaration is:
    ->add('firstDiscoveredAt', DateType::class, [
    'widget' => 'single_text',
    ])Could you do a bit of light here?
    Thanks!

  • 2017-10-18 Serge Boyko

    Right, didn't noticed that the type had changed. Thanks again!

  • 2017-10-18 Victor Bocharsky

    Hey Serge,

    Actually, browser does not know... Symfony does it. Well, we did "html => false" for this field in form type and that's why this field was rendered as simple "input type=text" field instead of "input type=date" HTML5 field. That's it. See option description in docs: https://symfony.com/doc/cur...

    Cheers!

  • 2017-10-18 Serge Boyko

    I have a small curiosity I hope you can answer. How does browser know that html5 should be disabled? I mean, there's no additional attributes that were added.

  • 2017-10-03 Diego Aguiar

    Hey Sergiu Popa

    Yeah, you need a different plugin if you are going to work with a full dates. Thanks for sharing!

    Have a nice day

  • 2017-10-03 Sergiu Popa

    If you need also time (DateTime), you can use this plugin: https://www.malot.fr/bootst...

    I used the format: dd-mm-yyyy hh:ii (dd-MM-yyyy hh:mm on Symfony Form Type)

  • 2017-09-20 Victor Bocharsky

    Hey Matias,

    Well, most often when you upload an image - you save its filename, or its relative web path in DB. If it's your case - then just query all those DB entries, pass them to template and iterate over them filling in src attributes of img tags with a proper paths you have.

    But if you do not store paths to images when upload them to the server, then you need to find all the image from your filesystem by yourself. Actually, it could be easily done with special libraries like Finder Component by Symfony, which is supplied with Symfony SE out of the box. In official docs you'll find many examples how to use it: https://symfony.com/doc/cur... . So in the controller, find all the images you want to render on the page with Finder, pass them to template and iterate over each file doing the same what I mention before: fill in src attributes of img tags with a proper paths. But in this case you will need to determine relative web path by yourself

    Cheers!

  • 2017-09-20 Matias Rouaux

    Hi! I have a question... how can i show a list of images that I have hosted in web/images using twig?? You explain how to get info from doctrine and bring it to do something like that:
    {% for element in list %}

    The element {{ element }}


    {% endfor %}

    But this time I dont have it in doctrine because there are images.
    I hope someone can understand my question haha
    Cheers!!

  • 2017-09-13 Diego Aguiar

    Hey Matias Rouaux

    I would believed that it should worked, but for some reason it doesn't. You may want to try passing an array to the placeholder option as mention in the docs https://symfony.com/doc/cur...
    or as this guy suggest, setting up a placeholder attribute on the element https://stackoverflow.com/a...
    If you are going to add it via FormType, just include it inside the "attr" array
    'attr' => [
    'placeholder' => 'Ingrese la fecha'
    ]

    Cheers!

  • 2017-09-13 Matias Rouaux

    Hi! I got a question, Can I add some placeholder text to de datepicker field? I tried something like this:
    ->add('descubiertoEn', DateType::class, array(
    'widget' => 'single_text',
    'attr' => [
    'class' => 'js-datepicker'
    ],
    'html5' => false,
    'placeholder' => 'Ingrese una fecha'
    ));
    But nothing happens.
    Cheers!

  • 2017-08-28 Victor Bocharsky

    Hey Alexey,

    You're right, this JS plugin works with a simple text field.

    Cheers!

  • 2017-08-28 Алексей Хромец

    It will be working only with 'widget' => 'single_text' parameter, right?

  • 2017-06-19 Victor Bocharsky

    Hey Agent,

    Hm, it's weird. It works for me well. What error did you have? Actually, we use schemaless links, i.e. "//cdnjs.cloudflare.com" instead of "https://cdnjs.cloudflare.com" there, maybe that's the case. Anyway, now the best practice is *always* require assets with HTTPS protocol when it available, so well done!

    Cheers!

  • 2017-06-17 Agent

    Hey there!

    just a little update, the Datepicker CSS and JavaScript hosting links for some reason aren't working here, i ended up solving this issue using this link from cdnjs.com


    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.6.4/css/bootstrap-datepicker.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.6.4/js/bootstrap-datepicker.min.js"></script>
  • 2017-05-29 Diego Aguiar

    Hey maxii123

    Are you talking about the javascript widget ? or the default behaviour of browser ?
    If option 1: I think you might forgotten to import the CSS file, can you double check it ? :)

    Have a nice day!

  • 2017-05-29 maxii123

    I'm not getting anything on my date field to indicate it's a live field / drop down. You have the little drop down arrow. What could I be missing?

  • 2017-04-06 Diego Aguiar

    Hey Jelle!

    I'm guessing you forgot to import the CSS file of the datepicker library, if that's not the case, could yo show me how your script looks like ?

    Have a nice day!

  • 2017-04-06 Jelle Schouwstra

    Hi, my datepicker is blank, what could this mean?

  • 2017-03-13 weaverryan

    Yo Tony C!

    Interesting! Actually, Chrome *should* support this - http://caniuse.com/#feat=in... - but there are some other browser that don't. And even if they did, it might look a bit different :). We'll add a note!

    Thanks!

  • 2017-03-13 Tony C

    'widget' => 'single_text' "already has some widget coolness"
    Not so much. At first I though there was something seriously wrong with the template. Just Chrome.
    Perhaps you might note that in the lesson BEFORE you assume we're using a browser that will do it automagically?

  • 2017-02-17 weaverryan

    Yo Macarena Paz Diaz Colomes!

    It's a small thing probably! It should be jQuery - notice the capitalization - it's a little j, not a big J :). And $ and jQuery are the same thing - they both point to the exact same function.

    Cheers!

  • 2017-02-16 Macarena Paz Diaz Colomes

    Hi, It's me again.
    I've got the error "JQuery is not defined".

    The code is this:
    JQuery(document).ready(function(){
    $('.js-datepicker').datepicker();
    })
    If I replace the 'JQuery' with '$', it works. Do you know why?

    Thanks!

  • 2017-01-26 Victor Bocharsky

    Hey Michael,

    Hahaha, you're hooked! :) Unfortunately, it's impossible with `bootstrap-datepicker` JS library. Actually, they have an issue about including time in this widget, so you can track it here: https://github.com/uxsoluti... . Or just use another JS library which support date/time picking - there're a lot of such libs on GitHub.

    Cheers!

  • 2017-01-26 Michael

    Hi
    Sorry, its me again, but I can't stop watching your tutorials and learn symfony;-)
    Is there an easy way to adapt it as a date- and timepicker field with the default date and time of now?
    Cheers Michael