Skip to content

Commit 80bbf4f

Browse files
committed
feature #589 [Twig] Add a strategy for adding a Stimulus controller to a Twig component (weaverryan)
This PR was squashed before being merged into the 2.x branch. Discussion ---------- [Twig] Add a strategy for adding a Stimulus controller to a Twig component …onent root element | Q | A | ------------- | --- | Bug fix? | yes-ish | New feature? | yes | Tickets | Fix #527 | License | MIT Hi! This allows adding a custom Stimulus controller to the root element of a component. The syntax is: ``` <div {{ attributes.add(stimulus_controller('my-controller', { someValue: 'foo' })) }}> ``` This is a compromise of having a nice syntax vs not duplicating code. The `attributes.add()` method is designed to work specifically with the `stimulus_*` functions, so it's name is kinda funny. But it feels way better than something like `attributes->stimulusController(stimulus_controller())`. Just doing `attributes.stimulusController('my-controller')` isn't possible at the moment, because it would require us to create a `StimulusControllersDto` and that, unfortunately, requires a Twig Environment for escaping purposes. Cheers! Commits ------- 2d2a137 [Twig] Add a strategy for adding a Stimulus controller to a Twig component
2 parents 6f15d5d + 2d2a137 commit 80bbf4f

File tree

5 files changed

+63
-2
lines changed

5 files changed

+63
-2
lines changed

src/LiveComponent/doc/index.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,15 @@ The following hooks are available (along with the arguments that are passed):
476476
* ``loading.state:finished`` args ``(element: HTMLElement)``
477477
* ``model:set`` args ``(model: string, value: any, component: Component)``
478478

479+
Adding a Stimulus Controller to your Component Root Element
480+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
481+
482+
To add a custom Stimulus controller to your root component element:
483+
484+
.. code-block:: twig
485+
486+
<div {{ attributes.add(stimulus_controller('my-controller', { someValue: 'foo' })) }}>
487+
479488
Loading States
480489
--------------
481490

src/TwigComponent/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
"require-dev": {
3636
"symfony/framework-bundle": "^5.4|^6.0",
3737
"symfony/phpunit-bridge": "^6.0",
38-
"symfony/twig-bundle": "^5.4|^6.0"
38+
"symfony/twig-bundle": "^5.4|^6.0",
39+
"symfony/webpack-encore-bundle": "^1.15"
3940
},
4041
"conflict": {
4142
"symfony/config": "<5.4.0"

src/TwigComponent/doc/index.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,12 @@ Set an attribute's value to ``null`` to exclude the value when rendering:
551551
{# renders as: #}
552552
<input type="text" value="" autofocus/>
553553
554+
To add a custom Stimulus controller to your root component element:
555+
556+
.. code-block:: twig
557+
558+
<div {{ attributes.add(stimulus_controller('my-controller', { someValue: 'foo' })) }}>
559+
554560
.. note::
555561

556562
You can adjust the attributes variable exposed in your template::

src/TwigComponent/src/ComponentAttributes.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@
1111

1212
namespace Symfony\UX\TwigComponent;
1313

14+
use Symfony\WebpackEncoreBundle\Dto\AbstractStimulusDto;
15+
1416
/**
1517
* @author Kevin Bond <[email protected]>
16-
1718
*
1819
* @immutable
1920
*/
@@ -94,4 +95,21 @@ public function without(string ...$keys): self
9495

9596
return $clone;
9697
}
98+
99+
public function add(AbstractStimulusDto $stimulusDto): self
100+
{
101+
$controllersAttributes = $stimulusDto->toArray();
102+
$attributes = $this->attributes;
103+
104+
$attributes['data-controller'] = implode(' ', array_merge(
105+
explode(' ', $attributes['data-controller']),
106+
explode(' ', $controllersAttributes['data-controller'] ?? [])
107+
));
108+
unset($controllersAttributes['data-controller']);
109+
110+
$clone = new self($attributes);
111+
112+
// add the remaining attributes for values/classes
113+
return $clone->defaults($controllersAttributes);
114+
}
97115
}

src/TwigComponent/tests/Unit/ComponentAttributesTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\UX\TwigComponent\ComponentAttributes;
16+
use Symfony\WebpackEncoreBundle\Dto\AbstractStimulusDto;
1617

1718
/**
1819
* @author Kevin Bond <[email protected]>
@@ -60,4 +61,30 @@ public function testCanGetWithout(): void
6061

6162
$this->assertSame(['class' => 'foo'], $attributes->without('style')->all());
6263
}
64+
65+
public function testCanAddStimulusController(): void
66+
{
67+
$attributes = new ComponentAttributes([
68+
'class' => 'foo',
69+
'data-controller' => 'live',
70+
'data-live-data-value' => '{}',
71+
]);
72+
73+
$controllerDto = $this->createMock(AbstractStimulusDto::class);
74+
$controllerDto->expects(self::once())
75+
->method('toArray')
76+
->willReturn([
77+
'data-controller' => 'foo bar',
78+
'data-foo-name-value' => 'ryan',
79+
]);
80+
81+
$attributes = $attributes->add($controllerDto);
82+
83+
$this->assertEquals([
84+
'class' => 'foo',
85+
'data-controller' => 'live foo bar',
86+
'data-live-data-value' => '{}',
87+
'data-foo-name-value' => 'ryan',
88+
], $attributes->all());
89+
}
6390
}

0 commit comments

Comments
 (0)