Skip to content

Commit 0f3f6e7

Browse files
authored
fix(ui): addFieldRow set modified (#9324)
Fixes #9264. When externally updating array or block rows through the `addFieldRow` or `replaceFieldRow` methods, nested rich text fields along with any custom components within them are never rendered. This is because unless the form is explicitly set to modified, as the default array and blocks fields currently do, the newly generated form-state will skip the rendering step. Now, the underlying callbacks themselves automatically set the form to modified to trigger rendering.
1 parent a50029f commit 0f3f6e7

File tree

9 files changed

+93
-10
lines changed

9 files changed

+93
-10
lines changed

packages/ui/src/fields/Array/index.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export const ArrayFieldComponent: ArrayFieldClientComponent = (props) => {
5252
schemaPath: schemaPathFromProps,
5353
validate,
5454
} = props
55+
5556
const schemaPath = schemaPathFromProps ?? name
5657

5758
const minRows = (minRowsProp ?? required) ? 1 : 0
@@ -129,13 +130,11 @@ export const ArrayFieldComponent: ArrayFieldClientComponent = (props) => {
129130
schemaPath,
130131
})
131132

132-
setModified(true)
133-
134133
setTimeout(() => {
135134
scrollToID(`${path}-row-${rowIndex}`)
136135
}, 0)
137136
},
138-
[addFieldRow, path, schemaPath, setModified],
137+
[addFieldRow, path, schemaPath],
139138
)
140139

141140
const duplicateRow = useCallback(

packages/ui/src/fields/Blocks/index.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,13 +116,11 @@ const BlocksFieldComponent: BlocksFieldClientComponent = (props) => {
116116
schemaPath,
117117
})
118118

119-
setModified(true)
120-
121119
setTimeout(() => {
122120
scrollToID(`${path}-row-${rowIndex + 1}`)
123121
}, 0)
124122
},
125-
[addFieldRow, path, schemaPath, setModified],
123+
[addFieldRow, path, schemaPath],
126124
)
127125

128126
const duplicateRow = useCallback(

packages/ui/src/forms/Form/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,8 @@ export const Form: React.FC<FormProps> = (props) => {
518518
rowIndex,
519519
subFieldState,
520520
})
521+
522+
setModified(true)
521523
},
522524
[dispatchFields, getDataByPath],
523525
)
@@ -541,6 +543,8 @@ export const Form: React.FC<FormProps> = (props) => {
541543
rowIndex,
542544
subFieldState,
543545
})
546+
547+
setModified(true)
544548
},
545549
[dispatchFields, getDataByPath],
546550
)

test/_community/payload-types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@ export interface Config {
4040
user: User & {
4141
collection: 'users';
4242
};
43-
jobs?: {
43+
jobs: {
4444
tasks: unknown;
45-
workflows?: unknown;
45+
workflows: unknown;
4646
};
4747
}
4848
export interface UserAuthOperations {
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
'use client'
2+
3+
import { useForm } from '@payloadcms/ui'
4+
5+
const AddRowButton = () => {
6+
const { addFieldRow } = useForm()
7+
8+
const handleClick = () => {
9+
addFieldRow({
10+
path: 'externallyUpdatedArray',
11+
schemaPath: 'externallyUpdatedArray',
12+
subFieldState: {
13+
text: {
14+
initialValue: 'Hello, world!',
15+
valid: true,
16+
value: 'Hello, world!',
17+
},
18+
},
19+
})
20+
}
21+
22+
return (
23+
<button id="updateArrayExternally" onClick={handleClick} type="button">
24+
Add Row
25+
</button>
26+
)
27+
}
28+
29+
export default AddRowButton
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import type { TextFieldServerComponent } from 'payload'
2+
3+
import { TextField } from '@payloadcms/ui'
4+
5+
export const CustomField: TextFieldServerComponent = ({ clientField, path }) => {
6+
return (
7+
<div id="custom-field">
8+
<TextField field={clientField} path={path as string} />
9+
</div>
10+
)
11+
}

test/fields/collections/Array/e2e.spec.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,4 +295,10 @@ describe('Array', () => {
295295
'Updated 3 Array Fields successfully.',
296296
)
297297
})
298+
299+
test('should externally update array rows and render custom fields', async () => {
300+
await page.goto(url.create)
301+
await page.locator('#updateArrayExternally').click()
302+
await expect(page.locator('#custom-field')).toBeVisible()
303+
})
298304
})

test/fields/collections/Array/index.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,30 @@ const ArrayFields: CollectionConfig = {
183183
},
184184
],
185185
},
186+
{
187+
name: 'externallyUpdatedArray',
188+
type: 'array',
189+
fields: [
190+
{
191+
name: 'customField',
192+
type: 'ui',
193+
admin: {
194+
components: {
195+
Field: '/collections/Array/CustomField.js#CustomField',
196+
},
197+
},
198+
},
199+
],
200+
},
201+
{
202+
name: 'ui',
203+
type: 'ui',
204+
admin: {
205+
components: {
206+
Field: '/collections/Array/AddRowButton.js',
207+
},
208+
},
209+
},
186210
],
187211
slug: arrayFieldsSlug,
188212
versions: true,

test/fields/payload-types.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,11 @@ export interface ArrayField {
465465
id?: string | null;
466466
}[]
467467
| null;
468+
externallyUpdatedArray?:
469+
| {
470+
id?: string | null;
471+
}[]
472+
| null;
468473
updatedAt: string;
469474
createdAt: string;
470475
}
@@ -2084,6 +2089,13 @@ export interface ArrayFieldsSelect<T extends boolean = true> {
20842089
};
20852090
id?: T;
20862091
};
2092+
externallyUpdatedArray?:
2093+
| T
2094+
| {
2095+
customField?: T;
2096+
id?: T;
2097+
};
2098+
ui?: T;
20872099
updatedAt?: T;
20882100
createdAt?: T;
20892101
}
@@ -3400,6 +3412,6 @@ export interface Auth {
34003412

34013413

34023414
declare module 'payload' {
3403-
// @ts-ignore
3415+
// @ts-ignore
34043416
export interface GeneratedTypes extends Config {}
3405-
}
3417+
}

0 commit comments

Comments
 (0)