Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine
This tutorial has a new version, check it out!

Creating a Date Picker Field

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $12.00

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!

47
Login or Register to join the conversation
Default user avatar
Default user avatar Matias Rouaux | posted 5 years ago

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!!

2 Reply

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!

Reply
Default user avatar
Default user avatar Matias Rouaux | posted 5 years ago

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!

1 Reply

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!

Reply
Lorena Avatar

Hi, just followed this tutorial but I ran into a problem. The datepicker doesn't show up next to the input field, rather when the field is clicked it shows up on the bottom left corner of the screen. I tried setting position attribute to it but nothing changes. Any ideas?

Reply

Hey @Lorena

This tutorial is pretty old, are you coding along with tutorial? I'm pretty sure that there is some version incompatibility between Bootstrap and datepicker

Cheers!

Reply
Default user avatar
Default user avatar Zeineb Ellili | posted 2 years ago

hey, i just tried to follow step by step this tutorial, but on my front-end page when i click to put the date, the calendar won't show up so that i can pick a date. and if i write it by hand it would insert it in my database as "null"! i'm really struggling with this i don't know what could be the error.

Reply

Hey Zeineb Ellili

that's odd. Can you double-check that you disabled HTML5 and the DatePicker JS library it's been loaded? Also double-check the CSS class on your form input.

Cheers!

Reply
Default user avatar
Default user avatar Zeineb Ellili | MolloKhan | posted 2 years ago | edited

i did disable the HTML5:

` ->add('date', DateTimeType::class,[

            'attr' => ['class' => 'form-control js-datepicker'],
            'label' => 'date de réservation',
            'required'=> false,
            'widget' =>'single_text',
           <b> 'html5' => false</b>,
            'format' => 'MM/dd/yyyy'
        ])  `

datePicker js library also loaded. :(

Reply

Ohh you're using a DateTimeType, I believe the JS library only works with a DateType input, give it a try :)

Reply
Default user avatar
Default user avatar Zeineb Ellili | MolloKhan | posted 2 years ago

i changed it and still nothing hahah, could be possibly from my template or html code?

Reply

Hey Zeineb Ellili!

Hmmm. It sounds like there are 2 possible issues, so let's look at each, one at a time :).

First, the date picker isn't showing up when you click the field. Do you see any JavaScript errors in your console? Also, try this:


        jQuery(document).ready(function() {
            // ...
            console.log($('.js-datepicker').length)
        });

That should log a number. What is it? If it's 1, great! But if it's 0, then for some reason your js-datepicker field isn't being found.

Second, you mentioned that if you fill in the field by hand and submit, it enters null into your database. That is... odd. The DateTimeType (or DateType) should validate your input. If the format you entered is valid it would insert a date. If you enter something invalid, it should cause a validation error on that field. If you enter something crazy like "banana", what happens? Something is very odd and wrong here...

Let me know what you find out!

Cheers!

Reply
Default user avatar
Default user avatar Zeineb Ellili | weaverryan | posted 2 years ago

it worked! thank you guys!

Reply
Default user avatar
Default user avatar codercoder123123 | posted 3 years ago

Hey Guys! How are you? I am really improving my skills in Symfony and right now I want to make a appointment form to choose date and hour for the meet and this hour will be reserveted. I am using Date picker, but converting is not going well. Can you suggest me something to do this task? Thanks in distance!

Reply

Hey codercoder123123,

You probably have 2 options:

1. Tweak Datepicker config to export date in a format that is default for DateTimeType Symfony form type.

2. Keep the Datepicker format and tweak DateTimeType format to match the one from Datepicker.

See a few options that might be useful for you:
https://symfony.com/doc/cur...
https://symfony.com/doc/cur...

I hope this helps!

Reply
Default user avatar
Default user avatar Tomitin | posted 4 years ago

Hello sir,

My DatePicker works perfectly but I have a serious problem. When I try to pick a date, a long list of the previous dates that i entered shows over, as you can imagine, it would be very annoying for the user if this appears. What can i do if a don't want to show this "autocompletion form list"? I know that I can disable it in chrome but like i said, it wouldn't be a good experience for an user. Thank you!

Reply

Hey Tomitin,

Hm, so if you do not want to show autocomplete that browsers show you - you can control it with the "autocomplete" attribute like:


<input type="text" autocomplete="off">

As soon as you set its value to "off" - browsers won't show the autocomplete for this field.

Cheers!

Reply
Default user avatar
Default user avatar batcat the cat | posted 4 years ago

Hey guys,
I follow the instructions (I promise), but I have just a black line on top the input and not a calendar.
If I remove 'html5' => false, then I have the calendar by the brower and black line.
I work with Symfony 3.4

Reply

Hey Batcat,

Hm, probably you point to an invalid resource, could you open Google Chrome Profiler and look at Console tab. Make sure to reload the page one more time with the opened profiler. Do you have any missing resources or 404 statuses? You can also look at Network tab as well.

Cheers!

Reply
Default user avatar
Default user avatar batcat the cat | Victor | posted 4 years ago

Dear Victor,

Yes I have missing resources... Here are my messages :
Erreur dans les liens source : request failed with status 404
URL de la ressource : http://localhost:8000/js/bootstrap.min.js
URL du lien source : bootstrap.min.js.map[En savoir plus]

Reply

Hey Batcat,

OK, that's something, so are you sure you have that file in web/ directory, i.e. "web/js/bootstrap.min.js" file? Probably you just forget to copy that file in the web/js/ direcotry or made a typo in filename.

Cheers!

Reply
Default user avatar
Default user avatar batcat the cat | Victor | posted 4 years ago

Hey Victor,

Problem resolved, I had a mistake in my path... Yes, shame on me ^^'
Thank you for your answers and your time!

Have a nice day

Reply

Hey Batcat!

Glad you got it working, good work! And I'm happy the problem wasn't on our side.

Cheers!

Reply
Sergiu P. Avatar
Sergiu P. Avatar Sergiu P. | posted 5 years ago

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)

Reply

Hey Sergiu P.

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

Have a nice day

Reply
Default user avatar

'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?

Reply

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!

1 Reply
Default user avatar
Default user avatar Macarena Paz Diaz Colomes | posted 5 years ago

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!

Reply

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!

Reply
Jelle S. Avatar
Jelle S. Avatar Jelle S. | posted 5 years ago

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

Reply

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!

Reply
Robertino V. Avatar
Robertino V. Avatar Robertino V. | posted 5 years ago

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!

Reply

Hey Robertino V.!

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!

Reply
Robertino V. Avatar

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.

Reply
Default user avatar
Default user avatar Agent | posted 5 years ago | edited

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>
Reply

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!

Reply
Michael-K Avatar
Michael-K Avatar Michael-K | posted 5 years ago

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

Reply

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!

Reply
mehdi Avatar

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

Reply

Hey mehdi!

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!

1 Reply

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.

Reply

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!

Reply

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

Reply

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

Reply

Hey Alexey,

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

Cheers!

Reply
Richard Avatar
Richard Avatar Richard | posted 5 years ago

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?

Reply

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!

Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.5.9",
        "symfony/symfony": "3.1.*", // v3.1.4
        "doctrine/orm": "^2.5", // v2.7.2
        "doctrine/doctrine-bundle": "^1.6", // 1.6.4
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
        "symfony/swiftmailer-bundle": "^2.3", // v2.3.11
        "symfony/monolog-bundle": "^2.8", // 2.11.1
        "symfony/polyfill-apcu": "^1.0", // v1.2.0
        "sensio/distribution-bundle": "^5.0", // v5.0.22
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.16
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.2
        "composer/package-versions-deprecated": "^1.11", // 1.11.99
        "knplabs/knp-markdown-bundle": "^1.4", // 1.4.2
        "doctrine/doctrine-migrations-bundle": "^1.1" // 1.1.1
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.0.7
        "symfony/phpunit-bridge": "^3.0", // v3.1.3
        "nelmio/alice": "^2.1", // 2.1.4
        "doctrine/doctrine-fixtures-bundle": "^2.3" // 2.3.0
    }
}
userVoice