fix(ui): array field state to return empty array instead of 0 (#11283)
### What? This PR fixes an issue where empty array fields would return `0` instead of an empty array `[]` in form state. The issue was caused by `rows` being initialized as `undefined` within the array field reducer. As a result, `rows` did not exist on array field state when initial state was empty. This has been updated to initialize as an empty array (`rows: []`) to ensure consistent behavior when using `getDataByPath`. Fixes #10712 --- - To see the specific tasks where the Asana app for GitHub is being used, see below: - https://app.asana.com/0/0/1211439284995184
This commit is contained in:
25
test/fields/collections/Array/GetDataByPathTest.tsx
Normal file
25
test/fields/collections/Array/GetDataByPathTest.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
'use client'
|
||||
|
||||
import { useForm } from '@payloadcms/ui'
|
||||
import React from 'react'
|
||||
|
||||
const GetDataByPathTest: React.FC = () => {
|
||||
const { getDataByPath } = useForm()
|
||||
|
||||
// Test the empty array field
|
||||
const emptyArrayResult = getDataByPath('potentiallyEmptyArray')
|
||||
|
||||
// Render the result directly so e2e test can easily read it
|
||||
return (
|
||||
<div id="getDataByPath-test">
|
||||
<span id="empty-array-result">
|
||||
{Array.isArray(emptyArrayResult) ? 'ARRAY' : String(emptyArrayResult)}
|
||||
</span>
|
||||
<span id="empty-array-length">
|
||||
{Array.isArray(emptyArrayResult) ? emptyArrayResult.length : 'NOT_ARRAY'}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default GetDataByPathTest
|
||||
@@ -637,4 +637,14 @@ describe('Array', () => {
|
||||
await expect(subArrayContainer2).toHaveCount(1)
|
||||
})
|
||||
})
|
||||
test('should return empty array from getDataByPath for array fields without rows', async () => {
|
||||
await page.goto(url.create)
|
||||
|
||||
// Wait for the test component to render
|
||||
await page.waitForSelector('#getDataByPath-test')
|
||||
|
||||
// Check that getDataByPath returned an empty array, not 0
|
||||
await expect(page.locator('#empty-array-result')).toHaveText('ARRAY')
|
||||
await expect(page.locator('#empty-array-length')).toHaveText('0')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -277,6 +277,15 @@ const ArrayFields: CollectionConfig = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'getDataByPathTest',
|
||||
type: 'ui',
|
||||
admin: {
|
||||
components: {
|
||||
Field: '/collections/Array/GetDataByPathTest.js',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
slug: arrayFieldsSlug,
|
||||
versions: true,
|
||||
|
||||
@@ -557,6 +557,54 @@ export interface BlockField {
|
||||
blockType: 'readOnlyBlock';
|
||||
}[]
|
||||
| null;
|
||||
/**
|
||||
* Change the value of this field to change the enabled blocks of the blocksWithDynamicFilterOptions field. If it's empty, all blocks are enabled.
|
||||
*/
|
||||
enabledBlocks?: string | null;
|
||||
blocksWithDynamicFilterOptions?:
|
||||
| (
|
||||
| {
|
||||
block1Text?: string | null;
|
||||
id?: string | null;
|
||||
blockName?: string | null;
|
||||
blockType: 'blockOne';
|
||||
}
|
||||
| {
|
||||
block2Text?: string | null;
|
||||
id?: string | null;
|
||||
blockName?: string | null;
|
||||
blockType: 'blockTwo';
|
||||
}
|
||||
| {
|
||||
block3Text?: string | null;
|
||||
id?: string | null;
|
||||
blockName?: string | null;
|
||||
blockType: 'blockThree';
|
||||
}
|
||||
)[]
|
||||
| null;
|
||||
blocksWithFilterOptions?:
|
||||
| (
|
||||
| {
|
||||
block1Text?: string | null;
|
||||
id?: string | null;
|
||||
blockName?: string | null;
|
||||
blockType: 'blockFour';
|
||||
}
|
||||
| {
|
||||
block2Text?: string | null;
|
||||
id?: string | null;
|
||||
blockName?: string | null;
|
||||
blockType: 'blockFive';
|
||||
}
|
||||
| {
|
||||
block3Text?: string | null;
|
||||
id?: string | null;
|
||||
blockName?: string | null;
|
||||
blockType: 'blockSix';
|
||||
}
|
||||
)[]
|
||||
| null;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
@@ -822,7 +870,7 @@ export interface ConditionalLogic {
|
||||
root: {
|
||||
type: string;
|
||||
children: {
|
||||
type: string;
|
||||
type: any;
|
||||
version: number;
|
||||
[k: string]: unknown;
|
||||
}[];
|
||||
@@ -2263,6 +2311,57 @@ export interface BlockFieldsSelect<T extends boolean = true> {
|
||||
blockName?: T;
|
||||
};
|
||||
};
|
||||
enabledBlocks?: T;
|
||||
blocksWithDynamicFilterOptions?:
|
||||
| T
|
||||
| {
|
||||
blockOne?:
|
||||
| T
|
||||
| {
|
||||
block1Text?: T;
|
||||
id?: T;
|
||||
blockName?: T;
|
||||
};
|
||||
blockTwo?:
|
||||
| T
|
||||
| {
|
||||
block2Text?: T;
|
||||
id?: T;
|
||||
blockName?: T;
|
||||
};
|
||||
blockThree?:
|
||||
| T
|
||||
| {
|
||||
block3Text?: T;
|
||||
id?: T;
|
||||
blockName?: T;
|
||||
};
|
||||
};
|
||||
blocksWithFilterOptions?:
|
||||
| T
|
||||
| {
|
||||
blockFour?:
|
||||
| T
|
||||
| {
|
||||
block1Text?: T;
|
||||
id?: T;
|
||||
blockName?: T;
|
||||
};
|
||||
blockFive?:
|
||||
| T
|
||||
| {
|
||||
block2Text?: T;
|
||||
id?: T;
|
||||
blockName?: T;
|
||||
};
|
||||
blockSix?:
|
||||
| T
|
||||
| {
|
||||
block3Text?: T;
|
||||
id?: T;
|
||||
blockName?: T;
|
||||
};
|
||||
};
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
|
||||
@@ -730,4 +730,43 @@ describe('Form State', () => {
|
||||
computedTitle: incomingStateFromServer.computedTitle, // This field was not modified locally, so should be updated from the server
|
||||
})
|
||||
})
|
||||
|
||||
it('should set rows to empty array for empty array fields', async () => {
|
||||
const req = await createLocalReq({ user }, payload)
|
||||
|
||||
// Create a document with an empty array
|
||||
const postData = await payload.create({
|
||||
collection: postsSlug,
|
||||
data: {
|
||||
title: 'Test Post',
|
||||
array: [], // Empty array - this should result in rows: [] in form state
|
||||
},
|
||||
})
|
||||
|
||||
const { state } = await buildFormState({
|
||||
mockRSCs: true,
|
||||
id: postData.id,
|
||||
collectionSlug: postsSlug,
|
||||
data: postData,
|
||||
docPermissions: {
|
||||
create: true,
|
||||
delete: true,
|
||||
fields: true,
|
||||
read: true,
|
||||
readVersions: true,
|
||||
update: true,
|
||||
},
|
||||
docPreferences: {
|
||||
fields: {},
|
||||
},
|
||||
documentFormState: undefined,
|
||||
operation: 'update',
|
||||
renderAllFields: false,
|
||||
req,
|
||||
schemaPath: postsSlug,
|
||||
})
|
||||
|
||||
expect(state.array).toBeDefined()
|
||||
expect(state?.array?.rows).toEqual([]) // should be [] not undefined
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user