Chapters
32 Chapters
|
4:16:27
|
Login to bookmark this video
-
Course Code
Subscribe to download the code!
Subscribe to download the code!
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Subtitles
Subscribe to download the subtitles!
Subscribe to download the subtitles!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Subscribe to jump to this part in the video!
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.
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": ">=8.2",
"ext-ctype": "*",
"ext-iconv": "*",
"babdev/pagerfanta-bundle": "4.x-dev", // 4.x-dev
"doctrine/doctrine-bundle": "^2.10", // 2.12.x-dev
"doctrine/doctrine-migrations-bundle": "^3.2", // 3.4.x-dev
"doctrine/orm": "^2.16", // 2.18.x-dev
"knplabs/knp-time-bundle": "dev-main", // dev-main
"pagerfanta/doctrine-orm-adapter": "4.x-dev", // 4.x-dev
"pagerfanta/twig": "4.x-dev", // 4.x-dev
"symfony/asset": "6.4.*", // 6.4.x-dev
"symfony/asset-mapper": "6.4.*", // 6.4.x-dev
"symfony/console": "6.4.x-dev", // 6.4.x-dev
"symfony/dotenv": "6.4.x-dev", // 6.4.x-dev
"symfony/flex": "^2", // 2.x-dev
"symfony/form": "6.4.x-dev", // 6.4.x-dev
"symfony/framework-bundle": "6.4.x-dev", // 6.4.x-dev
"symfony/monolog-bundle": "^3.0", // dev-master
"symfony/runtime": "6.4.x-dev", // 6.4.x-dev
"symfony/security-csrf": "6.4.x-dev", // 6.4.x-dev
"symfony/stimulus-bundle": "2.x-dev", // 2.x-dev
"symfony/twig-bundle": "6.4.x-dev", // 6.4.x-dev
"symfony/ux-autocomplete": "2.x-dev", // 2.x-dev
"symfony/ux-live-component": "2.x-dev", // 2.x-dev
"symfony/ux-turbo": "2.x-dev", // 2.x-dev
"symfony/ux-twig-component": "2.x-dev", // 2.x-dev
"symfony/validator": "6.4.x-dev", // 6.4.x-dev
"symfony/web-link": "6.4.*", // 6.4.x-dev
"symfony/yaml": "6.4.x-dev", // 6.4.x-dev
"symfonycasts/dynamic-forms": "dev-main", // dev-main
"symfonycasts/tailwind-bundle": "dev-main", // dev-main
"tales-from-a-dev/flowbite-bundle": "dev-main", // dev-main
"twig/extra-bundle": "^2.12|^3.0", // 3.x-dev
"twig/twig": "^2.12|^3.0" // 3.x-dev
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.4", // 3.6.x-dev
"phpunit/phpunit": "^9.5", // 9.6.x-dev
"symfony/browser-kit": "6.4.*", // 6.4.x-dev
"symfony/css-selector": "6.4.*", // 6.4.x-dev
"symfony/debug-bundle": "6.4.x-dev", // 6.4.x-dev
"symfony/maker-bundle": "^1.51", // dev-main
"symfony/panther": "^2.1", // v2.1.1
"symfony/phpunit-bridge": "7.1.x-dev", // 7.1.x-dev
"symfony/stopwatch": "6.4.x-dev", // 6.4.x-dev
"symfony/web-profiler-bundle": "6.4.x-dev", // 6.4.x-dev
"zenstruck/browser": "1.x-dev", // 1.x-dev
"zenstruck/foundry": "^1.36" // 1.x-dev
}
}
What JavaScript libraries does this tutorial use?
// importmap.php
return [
'app' => [
'path' => './assets/app.js',
'entrypoint' => true,
],
'js-confetti' => [
'version' => '0.11.0',
],
'@hotwired/stimulus' => [
'version' => '3.2.2',
],
'@symfony/stimulus-bundle' => [
'path' => './vendor/symfony/stimulus-bundle/assets/dist/loader.js',
],
'tom-select' => [
'version' => '2.3.1',
],
'tom-select/dist/css/tom-select.default.css' => [
'version' => '2.3.1',
'type' => 'css',
],
'@hotwired/turbo' => [
'version' => '7.3.0',
],
'stimulus-popover' => [
'version' => '6.2.0',
],
'debounce' => [
'version' => '1.2.1',
],
'turbo-view-transitions' => [
'version' => '0.3.0',
],
'stimulus-use' => [
'version' => '0.52.1',
],
'flowbite' => [
'version' => '2.2.1',
],
'@popperjs/core' => [
'version' => '2.11.8',
],
'flowbite-datepicker' => [
'version' => '1.2.6',
],
];
24 Comments
About the prepending: wouldn't it be better to update the entire table? In the video's example it works because of how it's sorted but if the table was sorted differently, the prepend would be weird (as the first row wouldn't necessarily be the new voyage).
Hey @kbond!
Yea, it probably would! By prepending the row, I'm sending a smaller payload back... but that's the kind of micro-optimization that I would not worry about at this point anyway :p. However, with both of these solutions, you need to be careful that, if you have pagination, your list is on page... else you're sending back a stream of page 1 to replace page 2 on the page (but as I mentioned, the same problem exists with my prepend row!). I think (though I still need to play with it more and see what patterns develop) the ultimate solution will be in Turbo 8. In Turbo 8, I believe we'll be able to send back a
<turbo-stream action="refresh"></turbo-stream>. This will simply tell whatever page you're on to "refresh". But combined with Turbo 8's morphing, the result should be:A) User makes an AJAX request to "refresh" whatever page they're on
B) The new HTML is "morphed" onto the existing. In other words, only elements that change are updated.
This is, if it all works as advertised, the promise land. To make matters more interesting, if you use Mercure, you could also publish an update to the users on your site with the same stream. For example, if a user is on the
/voyages/5show page, and you update theVoyageentity with id=5, you could send an update to anyone that is on that page that tells them to "refresh". VERY big possibilities with low burden on the dev / complexity.Cheers!
Hi, I came across this comment while trying to reload a table with sorting and pagination after adding an entry. I installed Turbo 8 and experimented with the 'refresh' action along with the
<meta name="turbo-refresh-method" content="morph">, and it works perfectly.However, there's one issue: the success flash message briefly appears but disappears immediately due to the refresh.
From my perspective, a solution would be to create a turbo-frame with a 'src' attribute for the table and move the table to a separate action/template. This frame could then be reloaded using
.reload()- similar to https://github.com/hotwired/turbo/issues/202#issuecomment-1977457984Does anybody has a other/better solution for this?
Ryan,
I saw this when I was looking for something else so I updated to Turbo 8 and used the action="refresh".
You stated:
A) User makes an AJAX request to "refresh" whatever page they're on
B) The new HTML is "morphed" onto the existing. In other words, only elements that change are updated.
This is my situation, I have an 'orders' form, and that form contains different check boxes that one can send the form too, but if someone fills out the 'orders' form, decides they want to add an e-mail to the form through a modal, then the success of that added e-mail form 'refreshes' the page, the contents of the order form are all cleared out from the refresh. I was looking for a solution to this when I found your response about Turbo 8 and it seemed perfect. My 'orders' form is rendered with a LiveComponent, and I use LiveCollection to add rows to the 'orders' form. Ideally what I was looking for was a way to have the success of the e-mail form submit from the modal trigger the re-render of the form through the LiveComponent. Is that possible? This doesn't work but I tried:
I was chasing this solution because I noticed if I fill out an input of the 'orders' form, a LiveUpdate is triggered and the new added e-mail shows up in the list.
Any suggestions are always much appreciated.
Hey @Brandon!
That's an interesting situation! I'm not sure if the
action="refresh"will help you here... though I really haven't played with what this pattern will allow yet.Your idea with live components is compelling. If I understand it correctly, after the user submits the email modal, if the form could be "re-rendered" at that moment, it would now be aware of the new email (because it's in the database) and render differently. Is that correct? If so, yea, asking the live component to re-render is worth a try :).
So, how best to do this? Hmm. Well, it may be overkill, but you can actually create custom stream types - e.g. you could have something like:
I'm not sure I've ever done this, but you would attach some custom JavaScript to this
rerenderaction. There, you could find the target, find the Component for it, then callcompoent.render()on that. Here are some docs on that - https://marcoroth.dev/posts/guide-to-custom-turbo-stream-actionsBecause, ultimately, there is no pure HTML change that you can make that would trigger the live component to re-render. Ultimately, you'll need to execute some JavaScript that then uses JS to re-render the component - https://symfony.com/bundles/ux-live-component/current/index.html#working-with-the-component-in-javascript
Let me know if you have any luck - I'm very curious about this :).
Cheers!
Ryan,
You have it correct, after the user submits the email modal, I would love for the form to re-render at that moment because it is in the database. I was looking for a pure HTML change that would trigger that, but if it doesn't exist I might try a custom stream action. I loathe JavaScript and try to avoid it where I can (that is why I jumped on LiveCollection, I got rid of a whole bunch using that!). I have 5 Stimulus controllers on my site and 4 of them were written by you through all these tutorials. I'll keep you posted on what I can figure out, thank you for all your work. I just finished off a major upgrade to my site following LAST stack tutorials and I have a overwhelming sense of accomplishment.
Hey @Brandon!
Yea, let me know how it goes! And congrats on the upgrade - I can tell you feel like I do when working with this stuff: it just feels right :). Let me know if the stream solution works out.
Cheers!
Hi !
I would like to make some extra validation client side with a stimulus controller like :
But it doesn't work, the response is not send to the <turbo-frame>
Any ideas how to make extra features before submiting stil using <turbo-frame> ?
Hey @ThierryGTH,
It looks like you need to do something like this
I hope it helps!
The submit() call work perfectly but the redirection from controller after form been submitted and validated (
$form->isSubmitted() && $form->isValid()) doesn't go to the turbo-frame.In other words, when you click manually on an submit button without interrupt the submitting process with (event.preventDefault()) every things goes like expected, but if you stop the submit process to do some staff and then submit afterward you are not going to have the same thing like just clicking the submit button without interrupting.
To deal with that, I had to replace my submit button by normal button with an stimulus submit action to fetch the form.
The this.element is the form element (stimulus controller declared in form tag)
Hey @ThierryGTH
I'm afraid I don't fully understand your problem. Is the
submit()call not working?Im hanging around on those flash messages for 2 days now. While normal flash messages work as expected, there is no flash message when the modal dialog is closing. I was rewriting and copy code as said for about 2 days now. Is there any way I can find out where the problem lies?
Hey Nexo,
Difficult to say, you will need to debug some thing deeper. There're a few possible issues:
display: noneCSS property.Try to debug it step by step using
dd(), make sure the flash message is set well with the correct key, made sure it's exist later before you're trying to read it, etc.I hope this help!
Cheers!
Thanks alot for the response, Victor.
While time passed, I found the problem. As a newbie with turbo, I got a bit confused about the turbo frames and how everything works together. The flash message got written just before the modal closed. At the end it was a matter of how and where to put that flash messages.
Thank you very much for the great tutorials. Keep up the good work.
Cheers
Nexo
Hey Nexo,
Awesome, I'm glad you figured it out yourself, well done! Yeah, all those Turbo-related topics are something new and it's easy to miss something simple. You just need to get used to it with more practice ;)
Cheers!
Sorry, I am newbie to the symfony and programming. I am curious is it should be so that select list opens inside of the modal and doesn`t overflow it?
I just find it not very comfortable, when the full list is not visible, and you don't see all the options.
Hey BlackRock,
Your problem sounds like a CSS problem in general, and I bet it could be fixed in CSS. But to understand it better, could you share a screenshot of your problem? You can upload it somewhere to image hosting like Imgur and send the link to it in the comment because we do not allow upload images directly to comments. Because I'm not sure I completely understand the problem. Do you have a behavior that is different from the one you see on this video?
Cheers!
Yes, I understand that this can be solved with CSS. I thought that this is obvious, and it should be written in the tutorial if it is important. That is why I am asking.
I am doing everything according to the text version of the tutorial.
Here is the link on the screen gif: https://i.imgur.com/CD11EfD.gif
Thank you!
Hey BlackRock,
Thank you for sharing a screenshot, it helped a lot to understand the problem. Yeah, I see what you mean, not perfect, but unfortunately, that's how HTML/CSS works in the current situation. The problem is that the dropdown list is added as an overlay over the other form HTML code, and so it does not push the dialog height. Fairly speaking, I'm not sure what would be the best workaround, but there're some that you may consider:
I hope this helps!
Cheers!
I added class 'overflow-visible' to the <dialog> and removed class 'overflow-auto' in the inner <div>. And everything worked
Hey @BlackRock!
I wonder if I was kind of solving the same issue in the last chapter - https://symfonycasts.com/screencast/last-stack/flowbite#making-the-modal-click-outside-smarter
I'm not actually changing the overflow behavior. But I was fixing a problem caused by something overflowing off of the bottom. Getting the overflow behavior correct was something I worked on quite a bit - but it wouldn't surprise me if it's not perfect (as it was complex).
What is the behavior when you changed to
overflow-auto? I just tried it and I didn't notice a difference - but perhaps I'm not looking closely enough :).Cheers!
Hey @weaverryan!
Sorry for some delay with the answer. Not sure if you have the same issue in the course. Because you write there:
So I assume, that you can see datepicker fully. The main issue is that it extends modal, but triggers <dialog>.
My issue is that I cannot see datepicker fully. Part of it hides inside of the <dialog>: https://i.imgur.com/yRsAacL.gif
This is the behavior if I leave all the tailwind classes as they are in the course.
If I add class 'overflow-visible' to the <dialog> and leave the class 'overflow-auto' in the inner <div>, then it won't limit datepicker, but will limit planets select list.
That is why I delete 'overflow-auto'.
Hey @BlackRock!
Sorry for the slow reply also on my end :). The video is super helpful! It turns out that I wasn't seeing the issue simply because I was using my touch pad to scroll vs actually trying to click on the scroll bar. Indeed, clicking on the scrollbar has the same effect for me.
I think the problem with your solution is that, if the content gets even longer, it will continue outside of the modal, without any scrolling. In this screenshot, I've duplicated the header a bunch of times - you can see it's starting to exit the modal. And there are even more headers below this that we can't see or scroll to https://imgur.com/z4urzkO
So, yes, there IS a problem here, but that's why I'm wondering if https://symfonycasts.com/screencast/last-stack/flowbite#making-the-modal-click-outside-smarter is actually the solution: it's expected that the datepicker won't be shown fully because the modal isn't big enough. But that fix should (I hope) allow you to scroll down. And, btw, in this example, another real-world solution might be to make the modal bigger - there's a lot of extra space.
Overall, I'm still not 100% satisfied with the overflow... but not sure what the perfect solution is yet.
Cheers!
Hey @weaverryan:)
If the content gets even longer, we can add some css to scroll these options.
Something like this:
Frankly, I doubt that https://symfonycasts.com/screencast/last-stack/flowbite#making-the-modal-click-outside-smarter is the solution exactly for the problem that I have. Because this code just makes sure that the click is inside the element, and nothing else.
"Houston: no signs of life"
Start the conversation!