diff --git a/src/LiveComponent/src/EventListener/DataModelPropsSubscriber.php b/src/LiveComponent/src/EventListener/DataModelPropsSubscriber.php index 8cc4ce37523..71b9602e224 100644 --- a/src/LiveComponent/src/EventListener/DataModelPropsSubscriber.php +++ b/src/LiveComponent/src/EventListener/DataModelPropsSubscriber.php @@ -65,6 +65,12 @@ public function onPreMount(PreMountEvent $event): void $childModel = $binding['child']; $parentModel = $binding['parent']; + // If the data-model attribute contains LiveComponent-specific modifiers, extract the actual property name + if (str_contains($parentModel, '|')) { + $parentModelParts = explode('|', $parentModel); + $parentModel = end($parentModelParts); + } + $data[$childModel] = $this->propertyAccessor->getValue($parentMountedComponent->getComponent(), $parentModel); } diff --git a/src/LiveComponent/tests/Fixtures/Component/ParentComponentDataModelWithModifiers.php b/src/LiveComponent/tests/Fixtures/Component/ParentComponentDataModelWithModifiers.php new file mode 100644 index 00000000000..26d091cbf18 --- /dev/null +++ b/src/LiveComponent/tests/Fixtures/Component/ParentComponentDataModelWithModifiers.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\UX\LiveComponent\Tests\Fixtures\Component; + +use Symfony\UX\LiveComponent\Attribute\AsLiveComponent; +use Symfony\UX\LiveComponent\Attribute\LiveProp; +use Symfony\UX\LiveComponent\DefaultActionTrait; + +#[AsLiveComponent('parent_component_data_model_with_modifiers')] +final class ParentComponentDataModelWithModifiers +{ + use DefaultActionTrait; +} diff --git a/src/LiveComponent/tests/Fixtures/Component/ParentComponentDataModelWithModifiers2.php b/src/LiveComponent/tests/Fixtures/Component/ParentComponentDataModelWithModifiers2.php new file mode 100644 index 00000000000..4fd598c6e0c --- /dev/null +++ b/src/LiveComponent/tests/Fixtures/Component/ParentComponentDataModelWithModifiers2.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\UX\LiveComponent\Tests\Fixtures\Component; + +use Symfony\UX\LiveComponent\Attribute\AsLiveComponent; +use Symfony\UX\LiveComponent\Attribute\LiveProp; +use Symfony\UX\LiveComponent\DefaultActionTrait; + +#[AsLiveComponent('parent_component_data_model_with_modifiers_2')] +final class ParentComponentDataModelWithModifiers2 +{ + use DefaultActionTrait; + + #[LiveProp(writable: true)] + public string $content; +} diff --git a/src/LiveComponent/tests/Fixtures/Component/ParentFormComponentWithModifiers.php b/src/LiveComponent/tests/Fixtures/Component/ParentFormComponentWithModifiers.php new file mode 100644 index 00000000000..391f34a230e --- /dev/null +++ b/src/LiveComponent/tests/Fixtures/Component/ParentFormComponentWithModifiers.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\UX\LiveComponent\Tests\Fixtures\Component; + +use Symfony\UX\LiveComponent\Attribute\AsLiveComponent; +use Symfony\UX\LiveComponent\DefaultActionTrait; + +#[AsLiveComponent('parent_form_component_with_modifiers')] +final class ParentFormComponentWithModifiers +{ + use DefaultActionTrait; + + public ?string $content = null; + + public ?string $content2 = null; +} diff --git a/src/LiveComponent/tests/Fixtures/templates/components/parent_component_data_model_with_modifiers.html.twig b/src/LiveComponent/tests/Fixtures/templates/components/parent_component_data_model_with_modifiers.html.twig new file mode 100644 index 00000000000..72982f2baf5 --- /dev/null +++ b/src/LiveComponent/tests/Fixtures/templates/components/parent_component_data_model_with_modifiers.html.twig @@ -0,0 +1,2 @@ +{% component parent_component_data_model_with_modifiers_2 with { content: 'default content on mount' } %} +{% endcomponent %} diff --git a/src/LiveComponent/tests/Fixtures/templates/components/parent_component_data_model_with_modifiers_2.html.twig b/src/LiveComponent/tests/Fixtures/templates/components/parent_component_data_model_with_modifiers_2.html.twig new file mode 100644 index 00000000000..aad832ff513 --- /dev/null +++ b/src/LiveComponent/tests/Fixtures/templates/components/parent_component_data_model_with_modifiers_2.html.twig @@ -0,0 +1,2 @@ +{{ component('textarea_component', { dataModel: 'norender|content' }) }} +{% component input_component with { dataModel: 'norender|content' } %}{% endcomponent %} diff --git a/src/LiveComponent/tests/Fixtures/templates/components/parent_form_component_with_modifiers.html.twig b/src/LiveComponent/tests/Fixtures/templates/components/parent_form_component_with_modifiers.html.twig new file mode 100644 index 00000000000..2d5d4b762de --- /dev/null +++ b/src/LiveComponent/tests/Fixtures/templates/components/parent_form_component_with_modifiers.html.twig @@ -0,0 +1,11 @@ +
+ {{ component('textarea_component', { + 'data-model': 'norender|content:value' + }) }} +
+ +
+ {{ component('textarea_component', { + 'dataModel': 'norender|content2:value' + }) }} +
diff --git a/src/LiveComponent/tests/Integration/EventListener/DataModelPropsSubscriberTest.php b/src/LiveComponent/tests/Integration/EventListener/DataModelPropsSubscriberTest.php index 7bdeb34d0ca..8a72207af0e 100644 --- a/src/LiveComponent/tests/Integration/EventListener/DataModelPropsSubscriberTest.php +++ b/src/LiveComponent/tests/Integration/EventListener/DataModelPropsSubscriberTest.php @@ -54,4 +54,38 @@ public function testDataModelPropsAreAvailableInEmbeddedComponents() $this->assertStringContainsString('', $html); $this->assertStringContainsString('', $html); } + + public function testDataModelPropsWithModifiersAreSharedToChild() + { + /** @var ComponentRenderer $renderer */ + $renderer = self::getContainer()->get('ux.twig_component.component_renderer'); + + $html = $renderer->createAndRender('parent_form_component_with_modifiers', [ + 'content' => 'Hello data-model!', + 'content2' => 'Value for second child', + 'attributes' => ['id' => 'dummy-live-id'], + ]); + + // Verify that the data-model attributes include the "norender" modifier and that values are passed correctly + $this->assertStringContainsString('', $html); + $this->assertStringContainsString('', $html); + } + + public function testDataModelPropsWithModifiersAreAvailableInEmbeddedComponents() + { + $templateName = 'components/parent_component_data_model_with_modifiers.html.twig'; + $obscuredName = '684c45bf85d3461dbe587407892e59d9'; + $this->addTemplateMap($obscuredName, $templateName); + + /** @var ComponentRenderer $renderer */ + $renderer = self::getContainer()->get('ux.twig_component.component_renderer'); + + $html = $renderer->createAndRender('parent_component_data_model_with_modifiers', [ + 'attributes' => ['id' => 'dummy-live-id'], + ]); + + // Verify that the data-model attributes include the "norender" modifier and that values are passed correctly + $this->assertStringContainsString('', $html); + $this->assertStringContainsString('', $html); + } }