Skip to content

Conversation

@weaverryan
Copy link
Owner

TODO (2) of symfony#500

This is all about establishing communication between a parent & child component. Suppose you have a parent form component with a $blogContent property. This component renders a child component (e.g. a reusable smart rich text editor) with a $value property.

The idea is that I want to pass my $blogContent property INTO the child as a prop called value. That can be done today, of course - e.g. {{ component('rich_editor', { value: blogContent }) }}. BUT, I also want that, when the value prop is modified by the end-user (e.g. they type into the rich text editor), that the new value is also set onto the parent component's blogContent prop. THAT's really what this feature is about.

Syntax to do this (from inside parent component's template):

{{ component('rich_editor', {
   'data-model': 'value:blogContent'
}) }}

Or simply 'data-model': 'blogContent' if your child prop is called value (it defaults to value).

To get this syntax/functionality, I'm looking at:

A) Vue https://vuejs.org/guide/components/events.html#usage-with-v-model

where <CustomComponent v-model="searchText"> is short for:

<CustomInput
  :modelValue="searchText"
  @update:modelValue="newValue => searchText = newValue"
/>

which translates to

  1. "please pass a modelValue prop into the child set to the parent component's searchText
    and
  2. When the modelValue changes inside the child, please set it onto the searchText prop on the parent

(note Vue used to use value as their default name with v-model but switched to modelValue - I'm not sure why).

B) From Alpine.js - x-modelable:

<div x-data="{ number: 5 }">
    <div x-data="{ count: 0 }" x-modelable="count" x-model="number">
        <button @click="count++">Increment</button>
    </div>
 
    Number: <span x-text="number"></span>
</div>

the x-model and x-modelable translate to:

A) Grab the number data from the parent scope and make it available as count in the child
and
B) When count in the child updates, please update the number in the parent

Cheers!

Copy link

@kbond kbond left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great!

*
* @internal
*/
final class DataModelPropsSubscriber implements EventSubscriberInterface
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious why you chose to put this in twig components? Is there value in having it here or just to make the transition from twig to live easier/consistent?

use PHPUnit\Framework\TestCase;
use Symfony\UX\TwigComponent\Util\ModelBindingParser;

final class ModeBindingParserTest extends TestCase
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
final class ModeBindingParserTest extends TestCase
final class ModelBindingParserTest extends TestCase

@@ -0,0 +1,5 @@
<div>
{{ component('textarea_component', {
'data-model': 'value:content'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should work w/o value:, right? Is this tested?

I see it's unit tested.

.. code-block:: twig
{{ component('textarea_field', {
'data-model': 'user.firstName:first user.lastName:last',
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤯 This is cool!

… components

This also includes the dispatching of several new PHP events.
@weaverryan weaverryan force-pushed the component-object-data-model branch from 7e7ebec to 13c6632 Compare November 1, 2022 14:30
@weaverryan weaverryan merged commit b5ad3ee into component-object Nov 1, 2022
@weaverryan weaverryan deleted the component-object-data-model branch November 1, 2022 14:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants