Skip to content

Conversation

@hbhalodia
Copy link
Contributor

What?

Closes #73342

Why?

How?

  • Update to use spread operator instead of deepMerge to fix the issue.

Testing Instructions

  1. Go to - https://wordpress.github.io/gutenberg/?path=/story/dataviews-dataform--layout-panel&args=openAs:modal
  2. Click on Tags to change.
  3. Try to remove/add the tags, it is working as expected.
  4. Check other fields as well and check if we have updated data.

Testing Instructions for Keyboard

  • Nil

Screenshots or screencast

Before

Screen.Recording.2025-11-17.at.2.20.43.PM.mov

After

Screen.Recording.2025-11-17.at.3.32.40.PM.mov

@github-actions
Copy link

github-actions bot commented Nov 17, 2025

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: hbhalodia <[email protected]>
Co-authored-by: ntsekouras <[email protected]>
Co-authored-by: oandregal <[email protected]>
Co-authored-by: straku <[email protected]>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@hbhalodia hbhalodia self-assigned this Nov 17, 2025
@hbhalodia hbhalodia added [Type] Bug An existing feature does not function as intended [Feature] DataViews Work surrounding upgrading and evolving views in the site editor and beyond [Package] DataViews /packages/dataviews labels Nov 17, 2025

const handleOnChange = ( newValue: Partial< Item > ) => {
setChanges( ( prev ) => deepMerge( prev, newValue ) );
setChanges( ( prev ) => ( { ...prev, ...newValue } ) );
Copy link
Contributor

@ntsekouras ntsekouras Nov 17, 2025

Choose a reason for hiding this comment

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

I'm not sure why we were using deepMerge in the first place but I might be missing context. @oandregal, @straku any insights?

Copy link
Member

@oandregal oandregal Nov 17, 2025

Choose a reason for hiding this comment

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

That's there for nested data. Here's a use case that breaks with these changes:

Before (current storybook):

Screen.Recording.2025-11-17.at.14.04.37.mov

After (with these changes): note how all other fields are cleared

Screen.Recording.2025-11-17.at.14.05.02.mov

Copy link
Contributor

@ntsekouras ntsekouras Nov 17, 2025

Choose a reason for hiding this comment

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

Does this mean though that the deepMerge usage is correct? Shouldn't a nested field handle that on setValue or something (have a way to control how the changes merge in parent props)? Current implementation is buggy (the issue for tokens) and feels like opinionated handling of changes.

Copy link
Member

Choose a reason for hiding this comment

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

Take the following example, add a new value to a field type array:

Screen.Recording.2025-11-17.at.14.57.17.mov

What do you expect to receive as values in the onChange callback of DataForm?

For any other control (single items, not arrays) it streams the changed value, so I expected Book reviews, but the array control streams all (existing and new). That's the core issue we need to figure out. I see two ways to go about this:

  1. make the array field type only stream the changes ("[ 'book reviews' ] ")
  2. make the array field type stream the whole list of values ("[ 'photography' , 'book reviews']")

Whatever we do here, we should do for objects as well (when we support them).

If we go with 1, for nested scenarios, deepMerge would work as it is (for both arrays and objects). If we go with 2 (current behavior), we need to tweak the merging algorithm to do the following: for arrays (and objects), do not merge, just take the incoming data.

Copy link
Contributor

@ntsekouras ntsekouras Nov 17, 2025

Choose a reason for hiding this comment

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

In general your option 1 can't work seamlessly because we can remove existing values, so we'd need to indicate that somehow without passing the whole new value.

Not sure how we can solve this (I'll have to familiarize myself more with the code), but it seems we can't have opinionated merging. I've mentioned a few times if setValue can help here, but in general for me it feels it should be the field that handles the merging somehow.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi @oandregal, If I am correct, are you saying need to update something like below?

diff --git a/packages/dataviews/src/stories/dataform.story.tsx b/packages/dataviews/src/stories/dataform.story.tsx
index 58b7226abc..ebafae27ed 100644
--- a/packages/dataviews/src/stories/dataform.story.tsx
+++ b/packages/dataviews/src/stories/dataform.story.tsx
@@ -2144,6 +2144,20 @@ const DataAdapterComponent = () => {
 			label: 'User Email',
 			type: 'email',
 		},
+		{
+			id: 'user.profile.tags',
+			label: 'User Tags',
+			type: 'array',
+			placeholder: 'Enter comma-separated tags',
+			description: 'Add tags separated by commas (e.g., "tag1, tag2, tag3")',
+			elements: [
+				{ value: 'astronomy', label: 'Astronomy' },
+				{ value: 'book-review', label: 'Book review' },
+				{ value: 'event', label: 'Event' },
+				{ value: 'photography', label: 'Photography' },
+				{ value: 'travel', label: 'Travel' },
+			],
+		},
 		// Example of adapting a data value to a control value
 		// by providing getValue/setValue methods.
 		{
@@ -2200,7 +2214,11 @@ const DataAdapterComponent = () => {
 		// Edits will respect the shape of the data
 		// because fields provide the proper information
 		// (via field.id or via field.setValue).
-		setData( ( prev ) => deepMerge( prev, edits ) );
+		setData( ( prev ) =>
+			deepMerge( prev, edits, {
+				arrayMerge: ( target, source ) => source,
+			} )
+		);
 	}, [] );
 
 	return (
@@ -2241,6 +2259,7 @@ const DataAdapterComponent = () => {
 							children: [
 								'user.profile.name',
 								'user.profile.email',
+								'user.profile.tags',
 							],
 						},
 					],

If not, Can you provide a example with type array which is nested type, that we can use here?

Copy link
Contributor

Choose a reason for hiding this comment

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

First, sorry for missing this scenario in the original PR 🙇

@hbhalodia @oandregal I like the idea of overwriting the original array with the new update. I don't see any obvious red flags for this approach.

Copy link
Member

Choose a reason for hiding this comment

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

Okay, so let's go with 2 (the current approach in the PR). While simple cases may work well for the 1 option (adding a single values), covering all the use cases will require a lot of complexity (think of: how do we rely that some values were removed?).

@hbhalodia yeah, thanks. An important note is to make sure that additional test would fail before this PR and that the changes her would fix it.

Copy link
Contributor Author

@hbhalodia hbhalodia Nov 18, 2025

Choose a reason for hiding this comment

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

Yep, will update the PR soon with the above changes.

An important note is to make sure that additional test would fail before this PR and that the changes her would fix it.

Not able to collect this? Can you please explain what needs to be done related to test.

Note: Updated the changes.

Thanks,

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hi @oandregal @ntsekouras @straku, The PR is also updated with latest changes. Can you please take a look on it?

Thanks,

@oandregal oandregal changed the title [DataForm] - Layout panel tags field (token field) misbehave when rendered in the modal - [#73342] DataForm: fix issue with array fields in layout panel Nov 24, 2025
Copy link
Member

@oandregal oandregal left a comment

Choose a reason for hiding this comment

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

Thanks for raising this bug and providing a fix, @hbhalodia

@oandregal
Copy link
Member

@hbhalodia the changelog needs to be updated, I can merge the PR when that's done.

@hbhalodia
Copy link
Contributor Author

Hi @oandregal, The changelog is now updated. Let me know if the sentence needs to be tweaked?

Thank You,

@oandregal oandregal merged commit 19158ce into WordPress:trunk Nov 25, 2025
33 checks passed
@github-actions github-actions bot added this to the Gutenberg 22.2 milestone Nov 25, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] DataViews Work surrounding upgrading and evolving views in the site editor and beyond [Package] DataViews /packages/dataviews [Type] Bug An existing feature does not function as intended

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[DataForm] - Layout panel tags field (token field) misbehave when rendered in the modal

4 participants