If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.
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.
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.
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.
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 |
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 | |
} |
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?
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.
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!
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!
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!
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?
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!
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.
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!
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. :(
Ohh you're using a DateTimeType, I believe the JS library only works with a DateType input, give it a try :)
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!
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!
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!
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!
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!
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
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!
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]
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!
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
Hey Batcat!
Glad you got it working, good work! And I'm happy the problem wasn't on our side.
Cheers!
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)
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
'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?
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!
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!
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!
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!
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!
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!
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.
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>
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!
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
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!
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
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!
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.
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!
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?
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!
// 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
}
}
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!!