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

Why data binding only works one-way at top level? #31

Closed
alvinsw opened this issue Feb 10, 2023 · 3 comments
Closed

Why data binding only works one-way at top level? #31

alvinsw opened this issue Feb 10, 2023 · 3 comments
Assignees
Labels
question Further information is requested

Comments

@alvinsw
Copy link

alvinsw commented Feb 10, 2023

I have tried using the crate-builder-component in a new simple Vue app and managed to get it running and displaying the crate data.
However I just found out that the crate data is bound only at top level.
For example, if you have data.crate = { ... } and pass it to :crate="data.crate", you can't do for example
data.crate['@graph'][7].name = 'abc' to update a value from outside of the compenent. And neither data.crate['@graph'][7].name is updated when the value in the text box is changed.
I know that we can use the @save:crate event to get the current/modified data.
But, is there a reason for not properly bound each nested property to its corresponding ui component?
It seems to be counterintuitive to how Vue component generally works.

@alvinsw alvinsw changed the title Why data binding only works at top level? Why data binding only works one-way at top level? Feb 10, 2023
@marcolarosa
Copy link
Contributor

marcolarosa commented Feb 12, 2023

You’ve asked two different questions whose answer is related.

To the first: why is the modified crate data not being reflected in the crate object outside the component.

The way it operates is by design. The component is intended to be a black box that has a defined interface to send data in and one to get data out. It is designed to completely encapsulate crate data handling internal to itself without needing to worry about side effects coming from outside.

To the second: why aren’t properties directly bound to UI elements.

With regard to the implementation; when the component ingests the crate it pulls it apart into an entities array and a properties array. Each entry in the properties array is an object with entityId, propertyId, property name, value and targetEntityId properties. When the crate is rendered to the UI each of these rows is passed into a component that knows how to handle it. For example, if it's a value and the profile says it should be a date then the date component is given the object to render a date picker.

When a user interacts with a data component (eg a text component or date or select) the new value is emitted and passed back up the tree to be patched into the internal structure. Or if a property is added, a placeholder is emitted and patched in to the properties array.

So the data always flows from the parent component to the relevant child component as properties (vue props which are immutable) and changes inside those components (at the edge) are emitted as a patch to the relevant object which is then handled at the top of the component tree. This is very much how vue (and other spa frameworks) data flow is supposed to work.

The design itself came from an earlier iteration of describo which used a database backend (with an entity table and a linked properties table) to store the crate and which worked exceedingly well with very large crates. Indeed this design also allows me to use the internals of this component in another product I’m working on that is database backed because in that case, the patch events can be sent to the db instead of the internal representation.

What you’ve described sounds a lot like what all of the frameworks stopped doing; namely, allowing changes to data in multiple places. In your description, if I’ve understood it correctly, changes could be happening far away from where the data is being handled and by the magic of JS pass by reference and two way data binding everything would remain in sync. That’s not the done thing nowadays.

Why do you want to pass in a crate and then manipulate it from the outer environment?

@marcolarosa marcolarosa self-assigned this Feb 12, 2023
@marcolarosa marcolarosa added the question Further information is requested label Feb 12, 2023
@alvinsw
Copy link
Author

alvinsw commented Feb 16, 2023

Thanks for explaining it. There is no use case for manipulating a crate from the outer environment yet.
It's just that from the user (of the Vue compoment) perspective, the convention is that a v-model binding to a component is usually two-ways. The one-say binding is normally done via {{ xxx }} and v-once. All the exisiting Vue component's library conforms to that convention, eg: element plus, naive ui, etc.

An example of the more complex component is an editable table such as: https://b-editable-table.muhimasri.com/guide/basic-usage.html
A user would expect that an object bound via a v-model will get an update from any changes to a cell and vice versa.

@marcolarosa
Copy link
Contributor

@alvinsw alvinsw closed this as completed Feb 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants