gstreamer0.10-ffmpeg
gstreamer0.10-plugins-good
packages.
Ok: time for Stimulus! First stimulus is... a JavaScript library! If you start a new project and install Encore fresh, like we did, then thanks to the recipe, stimulus
is already inside of your package.json
file.
We also have an @symfony/stimulus-bridge
library. This adds superpowers on top of stimulus. I'll tell you exactly what those are as we go along.
If you don't have these packages, install them with:
yarn add stimulus @symfony/stimulus-bridge --dev
Let me close a few tabs and open up our assets/app.js
file. This imports a bootstrap.js
file that the recipe also gave us. And you will need this: if you don't have it, you can get it from the code block on this page or the stimulus-bridge
docs.
The one line in this file starts stimulus by telling it to look for stimulus controllers in this controllers/
directory, which is literally assets/controllers/
. Symfony gives us one dummy controller to start.
And... yea, the entire point of this file is to say:
Hey Stimulus! I have some controllers in this
controllers/
directory.
We'll learn what all this weird lazy-controller
stuff is a bit later, it's not important yet.
The best way to see how Stimulus works is just to try it. Delete the hello_controller.js
file: let's create our first controller from scratch. Call it counter_controller.js
. To learn the Stimulus basics, we're going to create an element that tracks how many times we click it.
Oh and this naming convention is important. All of our controller files will be something_controller.js
. And you'll see why in a minute.
Tip
If you start a new project today, you'll be using Stimulus 3. You can check by looking in your
package.json
file for @hotwired/stimulus
. The only thing you need to change for Stimulus 3
is the import statement. Use:
import { Controller } from '@hotwired/stimulus';
Inside the file, these always start the same way: import {}
from stimulus
and what we want to import is Controller
. Then, export default
a class that extends Controller
. Inside the class, add a method called connect()
with this.element.innerHTML =
a message:
You have clicked zero times 😢
import { Controller } from 'stimulus'; | |
export default class extends Controller { | |
connect() { | |
this.element.innerHTML = 'You have clicked me 0 times ?'; | |
} | |
} |
That's all we need for now. To see what this does, we need to add a matching element to one of our pages. Open templates/product/index.html.twig
.
This is the template for the homepage. Down a bit, how about at the top of the main content, add <div data-controller="counter"></div>
.
... lines 1 - 2 | |
{% block body %} | |
... lines 4 - 9 | |
<div class="col-xs-12 col-9"> | |
... line 11 | |
<div data-controller="counter"></div> | |
... lines 13 - 82 | |
</div> | |
... lines 84 - 85 | |
{% endblock %} |
We can put something in the div
, but we don't need to for our example.
The data-controller
connects this element to the controller class that we just created. Because we named the file counter_controller.js
, the controller's name internally in Stimulus is counter
: it strips off the _controller.js
part.
So we connected the element to that controller with data-controller="counter"
. Thanks to that, this should work!
As a reminder, I still have a yarn watch
going over in my terminal, so it's been happily rebuilding each time we make a change.
Spin over to your browser and click to get to the homepage. Yes! It's alive! The empty div has our message! Inspect that element. Yep! We can see data-controller
and the text inside.
This is the magic of stimulus. As soon as it sees an element with data-controller="counter"
, it instantiates an instance of our "counter" controller and calls the connect()
method... named that way because Stimulus is "connecting" this object to a specific element on the page. And, as you can see, the element we just got connected to is available via this.element
.
That allowed us to easily set its inner HTML.
The beauty is that we can have as many of these elements on the page at the same time as we want. I'll copy the div
and, up in the aside
, paste.
... lines 1 - 2 | |
{% block body %} | |
... lines 4 - 5 | |
<aside class="col-xs-12 col-3"> | |
<div data-controller="counter"></div> | |
... line 8 | |
</aside> | |
... lines 11 - 86 | |
{% endblock %} |
Go refresh now. Two messages! And the really cool part is that each element is connected to a separate instance of our controller class. This means we get to write clean JavaScript code in a class and store information specific to its element as properties on that object. We'll do that very soon.
So... with Stimulus, we get objects that are bound to individual HTML elements and are instantiated automatically when those elements appear on the page. I would use Stimulus just for that! It's the simple, object-oriented JavaScript approach I've always tried to create on my own.
But wait there's more! Next: let's add a count
property and a click listener to show how each element is connected to a separate controller object. Then I'll show you the feature of Stimulus that absolutely knocked me over when I first saw it.
Hey Thomas,
Good question :) Well, the simple answer is because technically it's really a dev dependency :) You do not use any of your JS dependencies directly on the front end because everything is going through the Webpack Encore, i.e. the Webpack Encore compiles the final files into the public/build/ directory. And as soon as the files are compiled - you can even completely drop the node_modules/ directory, it will still work. From this point of you all your JS dependencies are just dev deps. But it's not that much important, you can put them in the "dependencies" section instead if you want, but that's not the best practice we recommend. That's it :)
Cheers!
Cheers!
Thank you very much for your answer Victor.
I think I am doing a confusion about dev dependencies and thiere good practices.
For example the good practice for jquery is also: npm install jquery --save-dev
But in reality when I go in the production mode I need jquery.
In my mind the good practice would have been to use, a testing module for example, in dev dependencies.
So why stimulus or jquery use the flag --save-dev ?
Do you uderstand what I mean ?
Hey Thomas,
Unfortunately, you do not use the jQuery directly in prod :) What you're actually using in prod is a compiled version of jQuery, i.e. Webpack Encore compiled it, added some internal code around the jQuery code, and put it into the public/build/ directory. So once again, even with jQuery, it's technically a dev dependency for your project because it's needed only for Webpack Encore which in turn will compile the final files for you.
I hope it clarifies thing for you. But as I said, do whatever you like, you can add it to the "dependencies" section and it will still work ;)
Cheers!
Ok thank you Victor.
So I imagine you mean that if I modify my jquery libraries It will became some production libraries ?
I my mind, developpement libraries, are libraries used in the developpement periode only like eslint. My confusion must come from here.
Anyway, thank you very much for your answers and your time.
Loving Stimulus, and using it in places where I had been using jQuery for just a bit of interactivity.
What's the proper way to load stimulus controllers from a Symfony bundle? I'm assuming that in the bundle I can create an assets/controllers directory, but then how do I configure the app using the bundle to look in that directory for controllers? Perhaps in controllers.json? Or in Webpack?
Thanks.
Hiya Tac-Tacelosky !
You have 2 options here - one is the more "automated" way that the actual UX packages work. And the second is a simpler, but more manual process, which is totally fine if you are the one installing the bundles into your app :).
First, in both cases, yea, it's common to have an assets/ or Resources/assets directory in your bundle. And then, a controllers subdirectory is fine - you can organize that part however you want. So that's totally correct. You'll also want to put a package.json file in that directory so that it looks like a real package. The name won't really matter - since it will be an internal JavaScript package. Example: https://github.com/symfony/ux/blob/main/src/Chartjs/Resources/assets/package.json
You'll notice in the above example that they have a src/ and dist/ directory, you shouldn't need to worry about that for your own bundles. Just have the source files.
Anyways, if I remember correctly, as soon as you have this assets/package.json or Resources/assets/package.json file, when you install the bundle into a project, Flex will automatically update the project's package.json to point to this. It will look something like:
"@tacman/your-package": "file:/vendor/tacman/your-package/assets"
Where @tacman/your-package
is whatever you named your package in the bundle's package.json file.
At this point (after running yarn install --force
, you have JavaScript package available! Woo! To expose its controllers to the project's Stimulus, this is where those 2 options come into play:
1) The simpler option
Go into assets/bootstrap.js
and import each controller and register with Stimulus. So
import TacController from '@tacman/your-package/controllers/tac-controller';
// ...
app.register('tac', TacController);
2) The more magic option
To mimic what the core UX packages do, add a section like this to your bundle's package.json file https://github.com/symfony/ux/blob/ddd7953dab49e990486044a6a9827f70c11a01c5/src/Chartjs/Resources/assets/package.json#L6-L15
NOW you will be able to go into the assets/controllers.json file and point to the new controller. Actually, if you NOW installed the bundle, Flex would update the controllers.json file automatically.
Let me know if you hit any bumps! Really happy you're digging Stimulus - me too!
Cheers!
Thanks, Ryan, this is great. Now that Symfony 6.1 has an easy way to configure bundles, do you think you'll do another tutorial, maybe one that includes a stimulus controller?
I still can't figure this out, I've added it as an issue to symfony/flex, can you take a look if you have some time? Bundles with stimulus controllers -- can't wait!
Hey Tac-Tacelosky!
Sorry for the slow reply! It looks like you figured it out. Tbh, I didn't even realize that they keyword was a requirement - that issue will likely help others.
Cheers!
Hello Ryan. I just have a problem. My Bundles package.json contains a working configuration. And this even worked when I wrote the given entries manually into the controllers.json of my test app. Anyway symfony flex don't update automaticly the controllers.json when I install the bundle via composer. Is there something I've been missing? Maybe I have to push a recipe to the Contrib repo? I mean somehow flex has to know where my package.json is...
Hey Michael,
Yeah, unfortunately, Flex won't update those files. You can create a recipe, but Flex just replace files instead of updating them, so it will mean that your recipe will update users custom configuration. The good part is that with git diff users can check the difference and merge configs. Btw, IIRC you can write a post-install message in the recipe, so it might be an another way telling your users to go there and copy the working config into their own configuration. So, it's up to you what way to choose.
Cheers!
Ok, thank you for your reply. Where can I find a working example for that kind of recipe? I searched one for Ux swup but did not found one. And there is something what confuses me - when I install one of the symfony-ux composer packages both the package.json and the controller.json files are updated and NOT just overwritten. But when I install my bundle none of these gets even touched - not overwritten or modified...
Hey Michael,
See symfony/webpack-encore-bundle recipe, it should have all that stuff like package.json, assets/controllers.json, etc. Here's the link to the latest version: https://github.com/symfony/... - but I suppose you're interested in manifest.json file where everything is configured. Also, it has an example of that post-install message I was talking about, see post-install.txt there.
I hope this helps!
Cheers!
Thank you Victor. I found the mistake by looking at ux-collection-bundle.
The problem was symfony-flex don't see the package.json
when its inside src/Resources/assets folder. The Resources folder has to be inside the project root to make this work.
Hey Michael,
Ah, yes, it makes sense, good catch! Thanks for sharing the problem with others
Cheers!
My question is now - Do I have to name my package inside the package.json after the symfony bundle? I guess yes. I tried to rename it (make it shorter) but it was not recognized anymore. Am I right, that renaming is not possible ?
Ok, I found this here the moment I wanted to ask the same :D.
So I did it. What's worth mentioning is you will not be able to use the controller in a "normal" way. You have to write for every thing (controller, target, value ...) for example
data-controller="tacman--your-package--tac"
data-tacman--your-package--tac-target="target"
Hey Michael B.!
It looks like you already answered your own question - nice! I think it would be nice (we actually need it for Symfony Live Components - https://github.com/symfony/... to be able to add an "name" key in your package's package.json file that would override the controller name to make it short. The reason this doesn't exist is... mostly due to potential collisions - i.e. 2 packages both naming their controllers "foo". Unfortunately, we can't simply allow the user to override the name in their controllers.json file because some packages include PHP helpers that output the controller's name (e.g. for data-controller or targets). So if the user can change it dynamically... those helpers would output the wrong controller name.
Anyways, I hope you found a solution that makes you happy - it's on my todo list to at least make it possible to shorten the name in the package.json file.
Cheers!
Oh, and one more thing. For the long, ugly names, using the helpers - like {{ stimulus_controller('tacman/your-package/tag') }}
or {{ stimulus_target() }}
can make them less ugly - the "/" are normalized into the "--".
Yes. I found the {{ stimulus_controller('tacman/your-package/tag') }} function and thats how I found out the right spelling for the data-controller ;). I don't want to use this function for a bundle but it's good to know about it for an app.
Thank you! Cheers!
@weaverryan I have a problem with vue_component
. Symfony says this is the way how you render a vue component. Now I tried that in a bundle-related setup. Imagine I have a core
and a ui
bundle. If I create a component inside the core
bundle (it's the "root" bundle) vue_component('Hello')
works but if I create the exact same component in my ui
bundle it doesn't work (with a different name of course). I always get the following error (in the console) "Error connecting controller >
Error: Vue controller "Test" does not exist. Possible values: Hello"
I checked the following:
controllers.json
file is there and holds the corresponding controllercore
to the ui
bundle (via node_modules folder) is there and worksdo you (or anyone) has an idea what I forget/do wrong?
Hi @Christian!
Apologies for the slow reply - was in deep in a tutorial!
Hmm, so let's see. The key part of getting this working is some code that you have, most likely in assets/app.js
. It should look something like this:
registerVueControllerComponents(require.context('./vue/controllers', true, /\\.vue$/));"
THAT is what tells the vue_component()
UX system where to find your vue controllers: inside assets/vue/controllers
. Anything in there will be available to vue_component()
. Anything NOT in there will not be. Unfortunately, I don't think that line is designed to be called multiple times: e.g. if you called this once to load from dir1 and again to load from dir2, I think that second call would override the first one.
So, not a full answer, but let me know if that helps :)
Cheers!
Update Stimulus to 3.2.x on symfony/webpack-encore-bundle
Hi,
I'm wondering when symfony/webpack-encore-bundle will support @hotwired/stimulus 3.2.x version.
There is a new Outlets function that is very useful.
Thanks!
Hey MAli,
Hm, I see the latest v4.2.0 Webpack Encore release allows "@hotwired/stimulus" ^3.0.0: https://github.com/symfony/webpack-encore/blob/v4.2.0/package.json#L58 - that means you should be able to update to the latest 3.x version without problems and start using those outlets. Did you try to upgrade? What exactly constraints you from upgrading to @hotwired/stimulus 3.2.x ?
Cheers!
Hey Victor,
I'm using this link to install encore(symfony/webpack-encore-bundle)
After running yarn install
I get @hotwired/stimulus version = 3.0.1 on node_modules folder.
I just want to upgrade stimulus to the latest version.
Can I do that manually by running yarn upgrade --scope @hotwired
?
wouldn't that effect symfony/webpack-encore-bundle ?
Hey MAli,
Yep, try to upgrade your Yarn deps manually. The problem is that you may have some dependencies installed and locked to specific versions that prevent you to install the latest "@hotwired/stimulus". I suppose you just need to try to update your Yarn dependencies as you suggested, or if it does not help - maybe try to upgrade ALL your Yarn dependencies - this should probably help. If not - then there might be a package installed that prevents you from upgrading to the latest Stimulus, but I bet the problem is not in webpack encore as you can see from its package.json file.
Cheers!
Thank you Victor,
It was very helpful. I'm going to upgrade all my yarn dependencies and it should work without any problem then.
Cheers!
Hey MAli,
Yeah, I think it should work. Good luck! Just keep in mind that if you upgrade some major versions - it may bring some BC breaks. But with patch/minor versions upgrade it should be OK I think
Cheers!
Hiiiii,
Need help for a specific development.
My app is embed in a website, but when the Stimulus start i have no controller initialize.
I get the debug log in my console, but the only trace i have is the Stimulus starting and start.
Any idea what happen ?
I also try to register the controller manually with app.register('tier-price', TierPriceController);
no more luck.
Hey Quentin!
Hmmm. Just to be sure:
My app is embed in a website
What do you mean by this?
I get the debug log in my console, but the only trace i have is the Stimulus starting and start.
So, obviously, this is a good sign: it means Stimulus is running :). Unless there is something VERY wrong, when a controller is not initialized, it is almost always because of some naming problem. Registering it manually with app.register()
is a very good way to try to debug things. When you load the page, do you see the data-controller="tier-price"
in your HTML? I would also try rebuilding Encore and doing a force refresh. This is one of those situations where the problem is usually some tiny thing.
Cheers!
My app is call by a website via an enoint that render my view. In this view i have my data controller and one action . When i render this view in à custom route in my app , everything work. But when i render in this Web site, via ajax , the controller is not registred. I have debug a litte bit and found when i print the Application class from stimulus bridge my controller is not in the symfonyCrontrollers variable.
The funy thing is that in the Router propertie I found an array with my controller...
Hey Quentin!
Hmm. So your app returns some HTML. And the other website makes an Ajax call and prints that HTML onto its page, right? Does that other page have Stimulus running? And if so, does that other website hold the code for your Stimulus controller? My guess is that there is some misconfiguration between where Stimulus & your controller is initialized.
Cheers!
Hello,
I want to ask how to pass .env variable to stimulus controller.
I am using libphonenumber-js and I am using this methodthis.phoneNumber = parsePhoneNumber(this.inputTarget.value, 'CZ');
.
I want to change 'CZ' with a variable from Symfony's .env...
Thank for reply
Hey Tomáš S.
I believe the way to go is to inject that value as a Stimulus controller value. You can get the env var from a Symfony Controller and pass it through your JS
Here are the docs for using Stimulus values https://stimulus.hotwired.d...
Cheers!
Hi,
yarn watch not working.
It worked with out any problem until yesterday but when I have made some changes and started yran watch it is not working/syncing.
- yarn watch shows no error message and says `webpack compiled successfully`
- yarn build works filne and gets me the latest changes
Any help please!
Hey MAli
What's your local dev environment setup? I used to run under Windows WSL 1 and it's very slow at reading files. You may be facing something similar
Uhmm, I'm not familiar with that environment but you may want to upgrade your tools, for example, upgrade Nodejs to the latest version, also Yarn's version, it may help
Besides that, you could search for tricks to optimize your setup performance
Cheers!
hello,
don't understand why ! but controller don't work for me ... ?
i follow exactly the same as the course ?
// composer.json
{
"require": {
"php": ">=8.1",
"ext-ctype": "*",
"ext-iconv": "*",
"composer/package-versions-deprecated": "1.11.99.1", // 1.11.99.1
"doctrine/annotations": "^1.0", // 1.11.1
"doctrine/doctrine-bundle": "^2.2", // 2.2.3
"doctrine/doctrine-migrations-bundle": "^3.0", // 3.0.2
"doctrine/orm": "^2.8", // 2.8.1
"phpdocumentor/reflection-docblock": "^5.2", // 5.2.2
"sensio/framework-extra-bundle": "^5.6", // v5.6.1
"symfony/asset": "5.2.*", // v5.2.3
"symfony/console": "5.2.*", // v5.2.3
"symfony/dotenv": "5.2.*", // v5.2.3
"symfony/flex": "^1.3.1", // v1.18.5
"symfony/form": "5.2.*", // v5.2.3
"symfony/framework-bundle": "5.2.*", // v5.2.3
"symfony/property-access": "5.2.*", // v5.2.3
"symfony/property-info": "5.2.*", // v5.2.3
"symfony/proxy-manager-bridge": "5.2.*", // v5.2.3
"symfony/security-bundle": "5.2.*", // v5.2.3
"symfony/serializer": "5.2.*", // v5.2.3
"symfony/twig-bundle": "5.2.*", // v5.2.3
"symfony/ux-chartjs": "^1.1", // v1.2.0
"symfony/validator": "5.2.*", // v5.2.3
"symfony/webpack-encore-bundle": "^1.9", // v1.11.1
"symfony/yaml": "5.2.*", // v5.2.3
"twig/extra-bundle": "^2.12|^3.0", // v3.2.1
"twig/intl-extra": "^3.2", // v3.2.1
"twig/twig": "^2.12|^3.0" // v3.2.1
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.0
"symfony/debug-bundle": "^5.2", // v5.2.3
"symfony/maker-bundle": "^1.27", // v1.30.0
"symfony/monolog-bundle": "^3.0", // v3.6.0
"symfony/stopwatch": "^5.2", // v5.2.3
"symfony/var-dumper": "^5.2", // v5.2.3
"symfony/web-profiler-bundle": "^5.2" // v5.2.3
}
}
// package.json
{
"devDependencies": {
"@babel/preset-react": "^7.0.0", // 7.12.13
"@popperjs/core": "^2.9.1", // 2.9.1
"@symfony/stimulus-bridge": "^2.0.0", // 2.1.0
"@symfony/ux-chartjs": "file:vendor/symfony/ux-chartjs/Resources/assets", // 1.1.0
"@symfony/webpack-encore": "^1.0.0", // 1.0.4
"bootstrap": "^5.0.0-beta2", // 5.0.0-beta2
"core-js": "^3.0.0", // 3.8.3
"jquery": "^3.6.0", // 3.6.0
"react": "^17.0.1", // 17.0.1
"react-dom": "^17.0.1", // 17.0.1
"regenerator-runtime": "^0.13.2", // 0.13.7
"stimulus": "^2.0.0", // 2.0.0
"stimulus-autocomplete": "^2.0.1-phylor-6095f2a9", // 2.0.1-phylor-6095f2a9
"stimulus-use": "^0.24.0-1", // 0.24.0-1
"sweetalert2": "^10.13.0", // 10.14.0
"webpack-bundle-analyzer": "^4.4.0", // 4.4.0
"webpack-notifier": "^1.6.0" // 1.13.0
}
}
Hi,
Would someone tell me why stimulus is in the dev dependencies ?
yarn add stimulus @symfony/stimulus-bridge --dev
Thanks