diff --git a/README.md b/README.md
index 81a5e3e7..e582536f 100644
--- a/README.md
+++ b/README.md
@@ -204,7 +204,7 @@ class ScriptNonceSubscriber implements EventSubscriberInterface
### stimulus_controller
This bundle also ships with a special `stimulus_controller()` Twig function
-that can be used to render [Stimulus Controllers & Values](https://stimulus.hotwired.dev/reference/values)
+that can be used to render [Stimulus Controllers & Values](https://stimulus.hotwired.dev/reference/values), [Outlets](https://stimulus.hotwired.dev/reference/outlets)
and [CSS Classes](https://stimulus.hotwired.dev/reference/css-classes).
See [stimulus-bridge](https://github.com/symfony/stimulus-bridge) for more details.
@@ -260,6 +260,17 @@ If you have multiple controllers on the same element, you can chain them as ther
```
+If you need to attach an [outlet](https://stimulus.hotwired.dev/reference/outlets) to the controller, you can call the `addOutlet()` method.
+
+For example:
+
+```twig
+
Hello
+
+
+Hello
+```
+
You can also retrieve the generated attributes as an array, which can be helpful e.g. for forms:
```twig
diff --git a/src/Dto/StimulusControllersDto.php b/src/Dto/StimulusControllersDto.php
index 973aa19a..e55b5c21 100644
--- a/src/Dto/StimulusControllersDto.php
+++ b/src/Dto/StimulusControllersDto.php
@@ -11,10 +11,13 @@
namespace Symfony\WebpackEncoreBundle\Dto;
+use Twig\Markup;
+
final class StimulusControllersDto extends AbstractStimulusDto
{
private $controllers = [];
private $values = [];
+ private $outlets = [];
private $classes = [];
public function addController(string $controllerName, array $controllerValues = [], array $controllerClasses = []): void
@@ -36,10 +39,21 @@ public function addController(string $controllerName, array $controllerValues =
foreach ($controllerClasses as $key => $class) {
$key = $this->escapeAsHtmlAttr($this->normalizeKeyName($key));
- $this->values['data-'.$controllerName.'-'.$key.'-class'] = $class;
+ $this->classes['data-'.$controllerName.'-'.$key.'-class'] = $class;
}
}
+ public function addOutlet(string $outletName, string $selector)
+ {
+ if (1 < \count($this->controllers)) {
+ throw new \LengthException('You cannot call addOutlet() method when passing more than one controller identifier to stimulus_controller() function');
+ }
+
+ $this->outlets['data-'.$this->controllers[0].'-'.$outletName.'-outlet'] = $selector;
+
+ return new Markup($this, 'UTF-8');
+ }
+
public function __toString(): string
{
if (0 === \count($this->controllers)) {
@@ -53,7 +67,10 @@ public function __toString(): string
}, array_keys($this->values), $this->values)).' '.
implode(' ', array_map(function (string $attribute, string $value): string {
return $attribute.'="'.$this->escapeAsHtmlAttr($value).'"';
- }, array_keys($this->classes), $this->classes))
+ }, array_keys($this->classes), $this->classes)).' '.
+ implode(' ', array_map(function (string $attribute, string $value): string {
+ return $attribute.'="'.$this->escapeAsHtmlAttr($value).'"';
+ }, array_keys($this->outlets), $this->outlets))
);
}
diff --git a/tests/Dto/StimulusControllersDtoTest.php b/tests/Dto/StimulusControllersDtoTest.php
index 2ef6fa0d..fa7e1adf 100644
--- a/tests/Dto/StimulusControllersDtoTest.php
+++ b/tests/Dto/StimulusControllersDtoTest.php
@@ -51,4 +51,20 @@ public function testToArrayNoEscapingAttributeValues(): void
$attributesArray
);
}
+
+ public function testAddOutlet(): void
+ {
+ $this->stimulusControllersDto->addController('foo', ['bar' => '"'], ['baz' => '"']);
+ $this->stimulusControllersDto->addOutlet('outlet-name', '"');
+ $attributesArray = $this->stimulusControllersDto->toArray();
+ self::assertSame(
+ [
+ 'data-controller' => 'foo',
+ 'data-foo-bar-value' => '"',
+ 'data-foo-baz-class' => '"',
+ 'data-foo-outlet-name-outlet' => '"',
+ ],
+ $attributesArray
+ );
+ }
}