fix(ui): properly differentiate between DOM events and raw values in setValue (#12892)

Because of this check, if a JSON with a property `target` was saved it
would become malformed.

For example trying to save a JSON field:

```json
{
  "target": {
    "value": {
      "foo": "bar"
    }
  }
}
```

would result in:

```json
{
  "foo": "bar"
}
```

And trying to save:

```json
{
  "target": "foo"
}
```

would just not save anything:

```json
null
```

I went through all of the field types and did not find a single one that
would rely on this ternary. Seems like it always defaulted to `const val
= e`, except the unexpected case described previously.

Fixes #12873

Added test may be overkill, will remove if so.




---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
  - https://app.asana.com/0/0/1210628466702813

---------

Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
This commit is contained in:
Anatoly Kopyl
2025-06-24 21:30:52 +03:00
committed by GitHub
parent b74969d720
commit c03e9c1724
2 changed files with 26 additions and 1 deletions

View File

@@ -77,7 +77,17 @@ export const useField = <TValue,>(options?: Options): FieldType<TValue> => {
// update field values from field component(s)
const setValue = useCallback(
(e, disableModifyingForm = false) => {
const val = e && e.target ? e.target.value : e
// TODO:
// There are no built-in fields that pass events into `e`.
// Remove this check in the next major version.
const isEvent =
e &&
typeof e === 'object' &&
typeof e.preventDefault === 'function' &&
typeof e.stopPropagation === 'function'
const val = isEvent ? e.target.value : e
dispatchField({
type: 'UPDATE',
disableFormData: disableFormData || (hasRows && val > 0),

View File

@@ -102,6 +102,21 @@ describe('JSON', () => {
)
})
test('should save field with "target" property', async () => {
const input = '{"target": "foo"}'
await page.goto(url.create)
const jsonCodeEditor = page.locator('.json-field .code-editor').first()
await expect(() => expect(jsonCodeEditor).toBeVisible()).toPass({
timeout: POLL_TOPASS_TIMEOUT,
})
const jsonFieldInputArea = page.locator('.json-field .inputarea').first()
await jsonFieldInputArea.fill(input)
await saveDocAndAssert(page)
const jsonField = page.locator('.json-field').first()
await expect(jsonField).toContainText('"target": "foo"')
})
test('should update', async () => {
const createdDoc = await payload.create({
collection: 'json-fields',