When using conditional statements on fields within a group, data from other groups returns undefined causing the application to crash on page load.
an example:
import { CollectionConfig } from "payload/types";
export const TestConfig: CollectionConfig = {
slug: 'testconfig',
fields: [
{
name: 'testGroup1',
type: 'group',
fields: [
{
name: 'testField1',
type: 'text',
}
]
},
{
name: 'testGroup2',
type: 'group',
fields: [
{
name: 'testField2',
type: 'text',
admin:{
condition: (data) => {
if (
data.testGroup1.testField1
) {
return true;
} else {
return false;
}
},
}
}
]
},
]
}
The conditional statement on the testField2 field does not evaluate correctly when creating a new document. The conditional statement can access the data when editing existing documents where testField1 is already populated, while it crashes the page when creating a new document
I'm currently running Payload 1.5.8
New document error stack trace:
TestConfig.ts:48 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'testField1')
at Object.condition (TestConfig.ts:48:51)
at iterateFields.js:12:1
at Array.forEach (<anonymous>)
at iterateFields (iterateFields.js:8:1)
at addFieldStatePromise (addFieldStatePromise.js:142:1)
at async Promise.all (index 0)
at async iterateFields (iterateFields.js:28:1)
at async Promise.all (index 1)
at async addFieldStatePromise (addFieldStatePromise.js:196:1)
at async Promise.all (index 0)
Hey @ToneseekerMusical — this is actually intended behavior, because when you create a document, there is no data yet. You should write your conditions so that you access those nested properties safely, in case there is no data. For example:
{
name: 'testField2',
type: 'text',
admin:{
condition: (data) => {
if (
data.testGroup1?.testField1 // added ?. instead of .
) {
return true;
} else {
return false;
}
},
}
}
Does that make sense? I will convert this to a discussion so we can keep conversation going.
Overall though it's a good practice to safely access nested data in conditions, because of the exact thing you're running into. The data structure might not be there yet!
It makes complete sense, I'm just dumb! I'll be sure to keep that in mind moving forward. This is the first time I've ever ran into this, and because I've never had my conditional statements return undefined despite never accessing them safely, I thought it was a bug. I appreciate the help!
Additionally, the following code crashes the application on editing existing documents, even if it has the roles
field set:
export const Users: CollectionConfig = {
slug: 'users',
auth: true,
admin: {
useAsTitle: 'email',
disableDuplicate: true,
},
access: {
create: () => true,
read: isAdminOrPartnerAdmin,
update: isAdminPartnerAdminOrSelf,
delete: isAdminPartnerAdminOrSelf,
},
fields: [
{
type: 'tabs',
tabs: [
{
label: 'User Info',
fields: [
{
type: 'group',
name: 'userInfo',
label: ' ',
fields: [
{
type: 'row',
fields: [
{
name: 'roles',
type: 'select',
required: true,
hasMany: true,
access: {
read: () => true,
create: isAdminOrPartnerAdminFieldLevel,
update: isAdminOrPartnerAdminFieldLevel,
},
defaultValue: 'customer',
options: [
{
label: 'Admin',
value: 'admin',
},
{
label: 'Employee',
value: 'employee',
},
{
label: 'Customer',
value: 'customer',
},
],
},
],
},
],
},
]
},
{
label: 'Instruments',
fields: [
{
name: 'instrumentInfo',
type: 'group',
label: ' ',
admin: {
condition: (data, siblingData) => {
if (
data.userInfo.roles &&
(data.userInfo.roles.includes('employee') ||
data.userInfo.roles.includes('customer'))
) {
return true;
} else {
return false;
}
},
},
fields: [
{
name: 'instruments',
type: 'relationship',
relationTo: 'instrument',
hasMany: true,
required: false,
access: {
read: () => true,
create: isAdminFieldLevel,
update: isAdminFieldLevel,
},
},
{
name: 'registerInstrument',
type: 'text',
admin: {
condition: (data, siblingData) => {
console.log(data.userInfo.roles)
if (data.userInfo.roles &&
data.userInfo.roles.includes('customer') {
return true;
} else {
return false;
}
},
},
},
],
}
],
},
],
},
],
};
the field that is causing the crash is registerInstrument
, when the conditional statement is removed, you can edit existing and create new users, and when the conditional statement is present, you cannot edit existing or create new users. The console.log
however, returns the value of the roles
field when attempting to edit existing users.