Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Free 3rd Party Controllers!

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

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

This search_preview controller has been an awesome example for us to learn how to make great-looking, functional things in Stimulus. But I have a confession: we didn't really need to do all this work! Why? Because someone already created an open source autocomplete Stimulus controller!

Hello stimulus-autocomplete!

Head to https://yarnpkg.com and search for "stimulus". You'll actually find a lot of Stimulus tools here that you can look through. What we're looking for is called stimulus-autocomplete. Here it is. Head to GitHub for find its documentation. Ooh! A GIF! Or.. GIF! This looks like exactly what we want!

Hello stimulus-components!

Before we implement this package, this is just one of many pre-made Stimulus controllers that exists out there. Let's take a quick tour-de-tools!

First up is Stimulus Components: a collection of a bunch of controllers... each with a fancy demo! Let's pick a random one - how about this Lightbox controller - and click into its demo. Yup! If you need to display photos in a Lightbox, there's a pre-made controller for that!

Hello TailwindCSS Stimulus Components!

If you use Tailwind CSS, check out the TailwindCSS Stimulus Components. It also has a demo with fun stuff inside, like a slide over, modals, tab functionality down here and more.

Hello stimulus-hotkeys!

Want to add keyboard shortcuts to your Stimulus controller? There's a tool for that: stimulus-hotkeys.

Hello stimulus-flatpickr

What about a date picker? Try the stimulus-flatpickr controller, which integrates the flatpickr JavaScript library.

And... that's not even everything! You can check out the Awesome Stimulus GitHub resource for more libraries, reading, podcasts, etc about Stimulus.

Hello BetterStimulus.com

One last interesting resource is betterstimulus.com, which holds a bunch of interesting patterns and best practices around Stimulus.

Installing stimulus-autocomplete

Anyways, let's get back to integrating this autocomplete controller. First, we need to install it! Copy the "yarn add" command, find your terminal and run:

yarn add "stimulus-autocomplete@2" --dev

Registering 3rd Party Controllers

So... once this finishes... how are we going to actually use this new controller? When we add a file to the assets/controllers/ directory, Stimulus automatically registers that as a controller, which means we can add a matching data-controller element to the page and it will work. When we install a Symfony UX package, the controllers.json does the same thing for those controllers.

{
"controllers": {
"@symfony/ux-chartjs": {
"chart": {
"enabled": true,
"fetch": "lazy"
}
}
},
"entrypoints": []
}

But what about the controller that we just installed? How do we register that with our Stimulus app? Back at the docs, under "Usage", you can see that they import the Autocomplete package... then call some application.register() thing to register this one controller.

But... which file should we add this code to? The answer is assets/bootstrap.js. Notice that this looks pretty similar to the code example, though not exactly the same. The application variable in the docs is the same as the app variable that we have in our file.

import { startStimulusApp } from '@symfony/stimulus-bridge';
// Registers Stimulus controllers from controllers.json and in the controllers/ directory
export const app = startStimulusApp(require.context(
'@symfony/stimulus-bridge/lazy-controller-loader!./controllers',
true,
/\.(j|t)sx?$/
));

On the docs, copy the import line and... pop that onto the top of our file. Then, to register the controller, down here say: app.register('autocomplete') - that name could be anything... and will determine the data-controller that will be used to connect to this controller in HTML - then Autocomplete.

... line 1
import { Autocomplete } from 'stimulus-autocomplete';
... lines 3 - 9
app.register('autocomplete', Autocomplete);
... lines 11 - 13

Congratulations! With 1 command and 2 lines of code, we now have a new controller called autocomplete available in our app!

Next: let's use this controller instead of our search-preview controller. It's going to be, well, refreshingly easy to drop in. Also: can we make this third-party controller load lazily... like we've done with some other controllers? Totally!

Leave a comment!

8
Login or Register to join the conversation
Tomasz-I Avatar
Tomasz-I Avatar Tomasz-I | posted 1 year ago

Hey @weaverryan do you have a solution you could share to somehow include controllers directory that is stored in a bundle? So except for including assets/controllers also to include vendor/myname/bundle/Resources/assets/controller? I cannot figure it out.

Reply

Hey Tomasz-I !

Hmm, that's an interesting question! You have a few options:

a) Simplest: Manually register them. With this solution, you're not loading an entire directory from a bundle, you just register the controllers you need one-by-one. I mention this first, because it's perfectly straightforward. In bootstrap.js:


import SomeImportedController from '../vendor/myname/bundle/Resources/assets/controller/some_controller.js';

// all the normal stuff

app.register('some_controller_name', SomeImportedController);

b) Next simplest, and more of what you are after: importing an entire directory. The startStimulusApp() function doesn't really have an "open door" to make this easy, so you just need to do it a bit more manually :).


import { startStimulusApp } from '@symfony/stimulus-bridge';
import { definitionsFromContext } from '@hotwired/stimulus-webpack-helpers';

// Registers Stimulus controllers from controllers.json and in the controllers/ directory
export const app = startStimulusApp(require.context(
    '@symfony/stimulus-bridge/lazy-controller-loader!./controllers',
    true,
    /\.[jt]sx?$/
));

app.load(definitionsFromContext(require.context(
    '@symfony/stimulus-bridge/lazy-controller-loader!../vendor/myname/bundle/Resources/assets/controller',
    true,
    /\.[jt]sx?$/
)));

I haven't tested that (so let me know!) but that should to the trick. The definitionsFromContext is normally called FOR you inside of startStimulusApp. So basically, this extra stuff at the bottom is replicating what happens inside of that function.

c) the fancy option. Cause, we like fancy things, right!

This option involves treating your application like a "ux package". This is two steps:

1) Add your "bundle" to package.json as a "package" under the "require"


"@vendor/your-bundle-name": "file: vendor/myname/bundle/Resources/assets"

Then run yarn install -f or npm install --force. You can actually use this part of the solution with solutions (a) and (b) if you want. It just means that, instead of referring to the paths with ../vednor/myname/bundle..., you can reference as @vendor/your-bundle-name/controller... which is kind of cool :).

Anyways, to register your controllers, you would update your controllers.json file to point at them:


{
    "controllers": {
        "@vendor/your-bundle-name": {
            "controller1": {
                "enabled": true,
                "fetch": "eager"
            }
        }
    },
    "entrypoints": []
}

This would create a controller called "@vendor/your-bundle-name/controller1". To tell the system exactly where this file lives, in your vendor/myname/bundle/Resources/assets directory, you would have a package.json file that would include, among the normal stuff, this:


    "symfony": {
        "controllers": {
            "controller1": {
                "main": "dist/controller1.js",
                "webpackMode": "eager",
                "fetch": "eager",
                "enabled": true
            }
        }
    },

The disadvantage of this is that... it's more work! And you can't load the entire directory automatically. The advantage would be if you are releasing a bundle that you would share with this world. By adding all of this config, when the user installs your bundle, their package.json and controllers.json files would automatically update, and they would get the new controller by doing zero other setup.

Phew! Probably a longer answer than you wanted, but I really liked the question :).

Cheers!

Reply
Default user avatar

I'm in the same class as Jay - trying to stay current with Symfony just for "fun" since 2.3. In a project in Symfony 6.0.6 & yarn 3.2.0, I tried to add
stimulus-autocomplete@2. Compiling webpack failed with:

"./node_modules/stimulus-autocomplete/dist/stimulus-autocomplete.js" contains a reference to the file "stimulus". This file can not be found, please check it for typos or update it if the file got moved.

So I did "yarn remove stimulus-autocomplete", followed by "yarn add stimulus-autocomple@3". Webpack compiled nicely.

Reply

Hey geoB!

> I'm in the same class as Jay - trying to stay current with Symfony just for "fun" since 2.3

That's impressive!

> In a project in Symfony 6.0.6 & yarn 3.2.0, I tried to add
stimulus-autocomplete@2. Compiling webpack failed with:

Yup, if you're in a fresh Symfony project (which will be using Stimulus 3), then you want the latest stimulus-autocomplete version (version 3). We recommended installing version 2 in this tutorial only because the actual code I'm using (and the code in the course download) using Stimulus 2. To be it simply: Stimulus 2 ❤️ stimulus-autocomplete 2, and Stimulus 3 ❤️ stimulus-autocomplete 3.

Cheers!

Reply
Jarrett Avatar
Jarrett Avatar Jarrett | posted 1 year ago

I had to "yarn add stimulus-autocomplete@2" to get javascripts to build without error. Latest stimulus-autocomplete is 3, which has stimulus 3 as a dependency. But when upgraded stimulus then stimulus-bridge was not happy, and once again javascripts would not build.
As an aside, any ballpark timeframe on getting stimulus-bridge to work with stimulus 3, Ryan? OR, does stimulus 3 add anything worth being hurried about? Maybe stick with stimulus 2?

Reply

Hey @Jay Gee!

Ah, yay! stimulus-autocomplete has been updated for Stimulus 3 - that's good news :). So, some excellent questions here. Let me do my best to answer them:

> I had to "yarn add stimulus-autocomplete@2" to get javascripts to build without error.

Thanks - we'll update the script & video to show that :).

> As an aside, any ballpark timeframe on getting stimulus-bridge to work with stimulus 3, Ryan?

All the PR's to do this already exist - https://github.com/symfony/... and https://github.com/symfony/.... We were mostly waiting for the ecosystem to start releasing support - like stimulus-autocomplete, but also stimulus-use (which has not released support yet) https://github.com/stimulus...

> OR, does stimulus 3 add anything worth being hurried about? Maybe stick with stimulus 2?

Stimulus 3 is... no big deal! They released a new major version basically because thy changed the name of the library from "stimulus" to "@hotwired/stimulus". If it weren't for that, v3 would be v 2.1. They DID add a couple of nice features - https://world.hey.com/hotwi... - but it's all pretty minor stuff.

Anyways, once Symfony UX DOES give you Stimulus v3, we'll be adding some notes to this tutorial to mention some things... but Stimulus v2 is basically identical to Stimulus v3.

Cheers!

Reply
Jarrett Avatar

Awesome, thanks for the swift and thorough reply Ryan! I will add that Symfonycasts (I started when it was KNP U) is a Godsend for me. I'm so thankful for you, Leanna, and the entire Symfonycast crew! I've been following Symfony since 2.3. Completely self-taught and it's not my everyday job. I will also say that Stimulus integration has been the most exciting thing for me since learning Symfony!

Reply

Hey @Jay Gee!

Ah, you've been around since Symfony 2.3! It's been awhile - and things were pretty crazy way back then. Thanks for sticking with us - even more impressive if this isn't your everyday job! It should be! ;)

> I will also say that Stimulus integration has been the most exciting thing for me since learning Symfony!

I feel that same way - along with Turbo. It's completely changed the JavaScript paradigm for me, and allowed me to get that single-page-app experience with a "normal" app. We've been prepping the SymfonyCasts codebase for Turbo (mostly be refactoring legacy JavaScript into Stimulus, of course) - and I'm super excited.

Cheers!

Reply
Cat in space

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

This tutorial works perfectly with Stimulus 3!

What PHP libraries does this tutorial use?

// 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
    }
}

What JavaScript libraries does this tutorial use?

// 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
    }
}
userVoice