Description
Link to reproduction
https://github.com/ysfaran/payload/tree/reproduction-after-change-bug
Describe the Bug
When you create an afterChange
hook for any nested field type like type: 'group'
the hook will set the value for previousValue
wrongly:
{
name: 'submenu',
type: 'group',
fields: [
{
name: 'name',
type: 'text',
defaultValue: 'initialValueSub',
hooks: {
afterChange: [
({ value, previousValue }) => {
// previousValue will store an unexpected value here
},
],
},
},
],
}
This happens because in the code the previousValue
of a field is always checked against the root of a collection/global. For example if you have this kind of structure defined in your collection/global:
{
name: 'rootValue',
group: {
name: 'subValue'
}
}
And you change the value of group.name
, then the previousValue
in the afterChange
hook would NOT be subValue
but rootValue
. This only happens because they have the same field name (here literally name
). If there is no root field with the same name previousValue
will always be undefined
.
I already applied a yarn patch
for my case and could work arround this with following diff:
diff --git a/dist/fields/hooks/afterChange/promise.js b/dist/fields/hooks/afterChange/promise.js
index 011ef42ed988077b15a636d93d582867764bb3fc..18ce7c068430f34a91fab83c6d69e106eae9e70c 100644
--- a/dist/fields/hooks/afterChange/promise.js
+++ b/dist/fields/hooks/afterChange/promise.js
@@ -26,7 +26,7 @@ const promise = async ({ collection, context, data, doc, field, global, operatio
originalDoc: doc,
previousDoc,
previousSiblingDoc,
- previousValue: previousDoc[field.name],
+ previousValue: previousSiblingDoc[field.name],
req,
siblingData,
value: siblingData[field.name]
diff --git a/dist/fields/hooks/afterChange/promise.js b/dist/fields/hooks/afterChange/promise.js
index 18ce7c068430f34a91fab83c6d69e106eae9e70c..d7b3b797a17ec43c2188c6505e2292f1492f60f5 100644
--- a/dist/fields/hooks/afterChange/promise.js
+++ b/dist/fields/hooks/afterChange/promise.js
@@ -50,7 +50,7 @@ const promise = async ({ collection, context, data, doc, field, global, operatio
global,
operation,
previousDoc,
- previousSiblingDoc: previousDoc[field.name],
+ previousSiblingDoc: (previousSiblingDoc?.[field.name]) || {},
req,
siblingData: (siblingData?.[field.name]) || {},
siblingDoc: siblingDoc[field.name]
But this would only fix it for the group
field type, not for other nested types like blocks
or array
.
I happy to file a PR the upcoming days, if no one takes it right away :)
To Reproduce
I will just use the example of the reproduction link here:
- Create a
Menu
Global like this:
import type { GlobalConfig } from '../../../../packages/payload/src/globals/config/types'
export const menuSlug = 'menu'
export const MenuGlobal: GlobalConfig = {
slug: menuSlug,
fields: [
{
name: 'name',
type: 'text',
defaultValue: 'initialValueRoot',
hooks: {
afterChange: [
({ value, previousValue }) => {
if (value !== previousValue) {
return `${previousValue} ${value}`
}
},
],
},
},
{
name: 'submenu',
type: 'group',
fields: [
{
name: 'name',
type: 'text',
defaultValue: 'initialValueSub',
hooks: {
afterChange: [
({ value, previousValue }) => {
if (value !== previousValue) {
return `${previousValue} ${value}`
}
},
],
},
},
],
},
],
}
- Change the value of the root field
name
in the admin panel and save. - This will now change the root field
name
toinitialValueRoot <the text you entered>
, but also unexpectedly thesubmenu.name
field toinitialValueRoot initialValueSub
.
Payload Version
2.5.0
Adapters and Plugins
No response