Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions docs/dev/guides/adding-stimulus-controllers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
title: "Adding Stimulus Controllers"
description: "How to add custom Stimulus controllers for the back end."
aliases:
- /guides/adding-stimulus-controllers/
---

Since Contao 5 now uses Turbo and Stimulus for the backend, sometimes it might not be enough to register JS assets for the backend as described under [Adding Backend assets][AddingBackendAssets], especially when listening for the `DOMContentLoaded` event.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of Stimulus by the Contao back end is irrelevant here - only the use of Turbo matters. But even that is not completely correct. Even the legacy JavaScript of the Contao back end might add, remove or modify existing DOM nodes, so it is always a good idea to write JavaScript that can handle any kind of DOM manipulation.


In this case it might be necessary to add a custom Stimulus controller.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not necessary, but Stimulus makes it way easier to implement what I mentioned above.


The following example assumes:
- You're using [Webpack Encore][SymfonyWebpackEncore] for asset management.
- You want to add code for a custom widget.

{{% notice info %}}
This guide is meant for bundle development.
{{% /notice %}}

### Adding a custom Stimulus controller

```js
// assets/controllers/my-custom-widget-controller.js
import { Controller } from "@hotwired/stimulus";

export default class MyCustomWidgetController extends Controller {
connect() {
// do your stuff
}

disconnect() {
this.#cleanup();
}

beforeCache() {
this.#cleanup();
}

#cleanup() {
// revert the markup before caching and when disconnecting
}


Comment on lines +42 to +43
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

}
```

### Adding your Stimulus application

```js
// assets/backend.js
import { Application } from "@hotwired/stimulus";
import MyCustomWidgetController from "./controllers/my-custom-widget-controller";

const application = Application.start();
application.register("my-vendor-prefix--my-custom-widget", MyCustomWidgetController);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
application.register("my-vendor-prefix--my-custom-widget", MyCustomWidgetController);
application.register('my-vendor-prefix--my-custom-widget', MyCustomWidgetController);


// Call the beforeCache() function on all controllers implementing it. This
// allows controllers to tear down things before the page gets put into cache.
// Note that Stimulus' disconnect() function will not fire at this point and
// thus cannot be used for this task.
document.documentElement.addEventListener('turbo:before-cache', (e) => {
for (const controller of application.controllers) {
if ('function' === typeof controller.beforeCache) {
controller.beforeCache(e);
}
}
});
```
Comment on lines +57 to +68
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we really need to include this bit here. I think it would be better to keep it short and simple and just refer to the internals here. Whether you want something to be executed before the page is being put into the cache really depends on the controller. Ideally a simple controller should not need to care.

@m-vo wdyt?


### Registering your Stimulus application

```json
// package.json
{
"devDependencies": {
"@hotwired/stimulus": "^3.2",
// any other dependencies you need for your controller/application
},
}
```

Read more about developing Stimulus controllers [here][StimulusControllers].

Regarding `#cleanup()` and `beforeCache()`, also check the notes on idempotency under [Turbo-compatible Stimulus controllers][StimulusBackend]

[AddingBackendAssets]: /guides/adding-back-end-assets
[SymfonyWebpackEncore]: https://symfony.com/doc/current/frontend/encore
[StimulusControllers]: https://stimulus.hotwired.dev/handbook/introduction
[StimulusBackend]: /internals/_stimulus-backend