Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Twig] ComponentAttributes::append()/prepend() #1531

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
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
5 changes: 5 additions & 0 deletions src/TwigComponent/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# CHANGELOG

## 2.16.0

- Add default value to `ComponentAttributes::render()` #1531
- Add `ComponentAttributes::append()/prepend()` #1531

## 2.15.0

- Add the ability to render specific attributes from the `attributes` variable #1442
Expand Down
19 changes: 13 additions & 6 deletions src/TwigComponent/doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -952,14 +952,21 @@ Render

The ability to *render* attributes was added in TwigComponents 2.15.

.. versionadded:: 2.16

The ability to *render* attributes with a default, *prepend*, and *append* were
added in TwigComponents 2.16.

You can take full control over the attributes that are rendered by using the
``render()`` method.
``render()``, ``prepend()``, and ``append()`` methods.

.. code-block:: html+twig

{# templates/components/MyComponent.html.twig #}
<div
style="{{ attributes.render('style') }} display:block;"
class="{{ attributes.render('class', 'default') }}" {# second parameter is the default value #}
style="{{ attributes.append('style', 'display:block;') }}" {# second parameter value to append #}
data-controller="{{ attributes.append('data-controller', 'hello-controller') }}" {# second parameter value to prepend #}
{{ attributes }} {# be sure to always render the remaining attributes! #}
>
My Component!
Expand All @@ -969,15 +976,15 @@ You can take full control over the attributes that are rendered by using the
{{ component('MyComponent', { style: 'color:red;' }) }}

{# renders as: #}
<div style="color:red; display:block;">
<div class="default" style="color:red; display:block;" data-controller="hello-controller">
My Component!
</div>

.. caution::

There are a few important things to know about using ``render()``:
There are a few important things to know about using ``render()``/``prepend()``/``append()``:

1. You need to be sure to call your ``render()`` methods before calling ``{{ attributes }}`` or some
1. You need to be sure to call these methods before calling ``{{ attributes }}`` or some
attributes could be rendered twice. For instance:

.. code-block:: html+twig
Expand All @@ -998,7 +1005,7 @@ You can take full control over the attributes that are rendered by using the
My Component!
</div>

2. If you add an attribute without calling ``render()``, it will be rendered twice. For instance:
2. If you add an attribute without calling these methods, it will be rendered twice. For instance:

.. code-block:: html+twig

Expand Down
14 changes: 12 additions & 2 deletions src/TwigComponent/src/ComponentAttributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,10 @@ public function __clone(): void
$this->rendered = [];
}

public function render(string $attribute): ?string
public function render(string $attribute, ?string $default = null): ?string
{
if (null === $value = $this->attributes[$attribute] ?? null) {
return null;
return $default;
}

if (!\is_string($value)) {
Expand All @@ -80,6 +80,16 @@ public function render(string $attribute): ?string
return $value;
}

public function prepend(string $attribute, string $value, string $separator = ' '): string
{
return trim(sprintf('%s%s%s', $value, $separator, $this->render($attribute)));
kbond marked this conversation as resolved.
Show resolved Hide resolved
}

public function append(string $attribute, string $value, string $separator = ' '): string
{
return trim(sprintf('%s%s%s', $this->render($attribute), $separator, $value));
}

/**
* @return array<string, string|bool>
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<div
foo="{{ attributes.render('foo') }}"
bar="{{ attributes.render('bar')|default('default') }}"
baz="default {{ attributes.render('baz') }}"
qux="{{ attributes.render('qux') }} default"
attr1="{{ attributes.render('attr1') }}"
attr2="{{ attributes.render('attr2')|default('default') }}"
attr3="default {{ attributes.render('attr3') }}"
attr4="{{ attributes.render('attr4') }} default"
attr5="{{ attributes.render('attr5', 'default') }}"
attr6="{{ attributes.prepend('attr6', 'default') }}"
attr7="{{ attributes.append('attr7', 'default') }}"
{{ attributes }}
/>
34 changes: 21 additions & 13 deletions src/TwigComponent/tests/Integration/ComponentExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
use Symfony\UX\TwigComponent\Tests\Fixtures\User;
use Twig\Environment;
use Twig\Error\RuntimeError;

/**
* @author Kevin Bond <kevinbond@gmail.com>
Expand Down Expand Up @@ -228,10 +227,13 @@ public static function renderingAttributesManuallyProvider(): iterable
['class' => 'block'],
<<<HTML
<div
foo=""
bar="default"
baz="default "
qux=" default"
attr1=""
attr2="default"
attr3="default "
attr4=" default"
attr5="default"
attr6="default"
attr7="default"
class="block"
/>
HTML,
Expand All @@ -240,17 +242,23 @@ class="block"
yield [
[
'class' => 'block',
'foo' => 'value',
'bar' => 'value',
'baz' => 'value',
'qux' => 'value',
'attr1' => 'value1',
'attr2' => 'value2',
'attr3' => 'value3',
'attr4' => 'value4',
'attr5' => 'value5',
'attr6' => 'value6',
'attr7' => 'value7',
],
<<<HTML
<div
foo="value"
bar="value"
baz="default value"
qux="value default"
attr1="value1"
attr2="value2"
attr3="default value3"
attr4="value4 default"
attr5="value5"
attr6="default value6"
attr7="value7 default"
class="block"
/>
HTML,
Expand Down
23 changes: 12 additions & 11 deletions src/TwigComponent/tests/Unit/ComponentAttributesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,20 +200,21 @@ public function testIsTraversableAndCountable(): void
$this->assertCount(1, $attributes);
}

public function testRenderSingleAttribute(): void
public function testRenderAttributes(): void
{
$attributes = new ComponentAttributes(['attr1' => 'value1', 'attr2' => 'value2']);

$this->assertSame('value1', $attributes->render('attr1'));
$this->assertNull($attributes->render('attr3'));
}

public function testRenderingSingleAttributeExcludesFromString(): void
{
$attributes = new ComponentAttributes(['attr1' => 'value1', 'attr2' => 'value2']);
$attributes = new ComponentAttributes([
'attr1' => 'value1',
'attr2' => 'value2',
'attr3' => 'value3',
'attr4' => 'value4',
]);

$this->assertSame('value1', $attributes->render('attr1'));
$this->assertSame(' attr2="value2"', (string) $attributes);
$this->assertSame('default value2', $attributes->prepend('attr2', 'default'));
$this->assertSame('value3 default', $attributes->append('attr3', 'default'));
$this->assertNull($attributes->render('attr5'));
$this->assertSame('default', $attributes->render('attr5', 'default'));
$this->assertSame(' attr4="value4"', (string) $attributes);
}

public function testCannotRenderNonStringAttribute(): void
Expand Down
Loading