Skip to content

Commit 095e5b8

Browse files
committed
[Twig][Live] null attribute values render without value (ie autofocus)
1 parent bb5b7c7 commit 095e5b8

File tree

7 files changed

+31
-9
lines changed

7 files changed

+31
-9
lines changed

src/LiveComponent/tests/Integration/LiveComponentHydratorTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,7 +274,7 @@ public function testCanDehydrateAndHydrateComponentsWithAttributes(): void
274274
$factory = self::getContainer()->get('ux.twig_component.component_factory');
275275

276276
/** @var ComponentWithAttributes $component */
277-
$component = $factory->create('with_attributes', $attributes = ['class' => 'foo']);
277+
$component = $factory->create('with_attributes', $attributes = ['class' => 'foo', 'value' => null]);
278278

279279
$this->assertSame($attributes, $component->attributes->all());
280280

src/TwigComponent/src/ComponentAttributes.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,13 @@ public function __toString(): string
3030
{
3131
return array_reduce(
3232
array_keys($this->attributes),
33-
fn (string $carry, string $key) => sprintf('%s %s="%s"', $carry, $key, $this->attributes[$key]),
33+
function (string $carry, string $key) {
34+
if (null === $this->attributes[$key]) {
35+
return "{$carry} {$key}";
36+
}
37+
38+
return sprintf('%s %s="%s"', $carry, $key, $this->attributes[$key]);
39+
},
3440
''
3541
);
3642
}

src/TwigComponent/src/HasAttributesTrait.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ public function mountAttributes(array $data): array
4545
}
4646

4747
foreach ($data as $key => $value) {
48-
if (!is_scalar($value)) {
49-
throw new \LogicException(sprintf('Unable to use "%s" (%s) as an attribute. Attributes must be scalar. If you meant to mount this value on your component, make sure this is a writable property.', $key, get_debug_type($value)));
48+
if (!is_scalar($value) && null !== $value) {
49+
throw new \LogicException(sprintf('Unable to use "%s" (%s) as an attribute. Attributes must be scalar or null. If you meant to mount this value on your component, make sure this is a writable property.', $key, get_debug_type($value)));
5050
}
5151
}
5252

src/TwigComponent/src/Resources/doc/index.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,17 @@ When rendering the component, you can pass an array of html attributes to add:
454454
My Component!
455455
</div>
456456
457+
Set an attribute's value to ``null`` to exclude the value:
458+
459+
.. code-block:: twig
460+
461+
{{ component('my_component', { hidden: null }) }}
462+
463+
{# renders as: #}
464+
<div hidden>
465+
My Component!
466+
</div>
467+
457468
Defaults & Merging
458469
~~~~~~~~~~~~~~~~~~
459470

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{{ component('component_a', { propA: 'prop a value', propB: 'prop b value' }) }}
2-
{{ component('with_attributes', { prop: 'prop value 1', class: 'bar', style: 'color:red;' }) }}
2+
{{ component('with_attributes', { prop: 'prop value 1', class: 'bar', style: 'color:red;', value: '', autofocus: null }) }}
33
{{ component('with_attributes', { prop: 'prop value 2', attributes: { class: 'baz' }, type: 'submit', style: 'color:red;' }) }}

src/TwigComponent/tests/Integration/ComponentExtensionTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public function testCanRenderComponentWithAttributes(): void
6060
$output = self::getContainer()->get(Environment::class)->render('template_a.html.twig');
6161

6262
$this->assertStringContainsString('Component Content (prop value 1)', $output);
63-
$this->assertStringContainsString('<button class="foo bar" type="button" style="color:red;">', $output);
63+
$this->assertStringContainsString('<button class="foo bar" type="button" style="color:red;" value="" autofocus>', $output);
6464
$this->assertStringContainsString('Component Content (prop value 2)', $output);
6565
$this->assertStringContainsString('<button class="foo baz" type="submit" style="color:red;">', $output);
6666
}

src/TwigComponent/tests/Unit/ComponentAttributesTest.php

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,14 @@ final class ComponentAttributesTest extends TestCase
2121
{
2222
public function testCanConvertToString(): void
2323
{
24-
$attributes = new ComponentAttributes(['class' => 'foo', 'style' => 'color:black;']);
25-
26-
$this->assertSame(' class="foo" style="color:black;"', (string) $attributes);
24+
$attributes = new ComponentAttributes([
25+
'class' => 'foo',
26+
'style' => 'color:black;',
27+
'value' => '',
28+
'autofocus' => null,
29+
]);
30+
31+
$this->assertSame(' class="foo" style="color:black;" value="" autofocus', (string) $attributes);
2732
}
2833

2934
public function testCanSetDefaults(): void

0 commit comments

Comments
 (0)