diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Handler/Examples.tsx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Handler/Examples.tsx index 866b463be8b..60c2e8e1713 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Handler/Examples.tsx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Handler/Examples.tsx @@ -408,7 +408,9 @@ export const TransformData = () => { const transformedData = transformData( data, ({ value, displayValue, label }) => { - return { value, displayValue, label } + if (!Array.isArray(value)) { + return { value, displayValue, label } + } }, ) diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Handler/info.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Handler/info.mdx index 049f4cb2ad4..97fa2010338 100644 --- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Handler/info.mdx +++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Form/Handler/info.mdx @@ -339,3 +339,35 @@ The callback function receives the following arguments as an object: Most of the fields will return the `displayValue` as a string. But there are some exceptions: - [ArraySelection](/uilib/extensions/forms/base-fields/ArraySelection/) will return the displayed/active options content as an array that contains a string (or React.ReactNode). + +##### `displayValue` from fields inside Iterate.Array + +When using the `Iterate.Array` component, you may check if the current entry is an array. This way you ensure you never transform the array itself, but only the values from the fields inside the array. + +```jsx +import { Form } from '@dnb/eufemia/extensions/forms' + +const MyForm = () => { + return ( + { + const transformedData = transformData( + data, + ({ value, displayValue, label }) => { + if (!Array.isArray(value)) { + return { value, displayValue, label } + } + }, + ) + }} + > + + + + + + + + ) +} +``` diff --git a/packages/dnb-eufemia/src/extensions/forms/DataContext/Provider/Provider.tsx b/packages/dnb-eufemia/src/extensions/forms/DataContext/Provider/Provider.tsx index e584077c70c..4e405c32c10 100644 --- a/packages/dnb-eufemia/src/extensions/forms/DataContext/Provider/Provider.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/DataContext/Provider/Provider.tsx @@ -424,8 +424,13 @@ export default function Provider( * Mutate the data set based on the filterData function */ const mutateDataHandler = useCallback( - (data: Data, handler: TransformData | FilterData, remove = false) => { - const mutate = (path: Path, result: boolean | unknown) => { + ( + data: Data, + handler: TransformData | FilterData, + { remove = false, mutate = true } = {} + ) => { + const freshData = {} as Data + const mutateEntry = (path: Path, result: boolean | unknown) => { if (remove) { if (result === false) { data = structuredClone(data) @@ -433,8 +438,12 @@ export default function Provider( } } else { if (typeof result !== 'undefined') { - data = structuredClone(data) - pointer.set(data, path, result) + if (mutate) { + data = structuredClone(data) + pointer.set(data, path, result) + } else { + pointer.set(freshData, path, result) + } } } } @@ -458,11 +467,15 @@ export default function Provider( props, internal, }) - mutate(path, result) + mutateEntry(path, result) } } ) + if (!mutate) { + return freshData + } + return data } else if (handler) { const runFilter = ({ path, condition }) => { @@ -480,7 +493,7 @@ export default function Provider( internal, }) : condition - mutate(path, result) + mutateEntry(path, result) } } @@ -567,7 +580,7 @@ export default function Provider( const filterDataHandler = useCallback( (data: Data, filter: FilterData) => { if (filter) { - return mutateDataHandler(data, filter, true) + return mutateDataHandler(data, filter, { remove: true }) } return data @@ -1176,7 +1189,7 @@ export default function Provider( } const transformData = (data: Data, handler: TransformData) => { - return mutateDataHandler(data, handler) + return mutateDataHandler(data, handler, { mutate: false }) } const formElement = formElementRef.current diff --git a/packages/dnb-eufemia/src/extensions/forms/DataContext/Provider/__tests__/Provider.test.tsx b/packages/dnb-eufemia/src/extensions/forms/DataContext/Provider/__tests__/Provider.test.tsx index 0de80d238f4..2281a12c80f 100644 --- a/packages/dnb-eufemia/src/extensions/forms/DataContext/Provider/__tests__/Provider.test.tsx +++ b/packages/dnb-eufemia/src/extensions/forms/DataContext/Provider/__tests__/Provider.test.tsx @@ -23,6 +23,7 @@ import { OnChange, DataValueWriteProps, OnSubmit, + Iterate, } from '../../../' import { isCI } from 'repo-utils' import { Props as StringFieldProps } from '../../../Field/String' @@ -4883,6 +4884,70 @@ describe('DataContext.Provider', () => { }) }) + it('should transform data with "transformData" from fields inside Iterate', async () => { + let transformedData = undefined + const onSubmit = jest.fn((data, { transformData }) => { + transformedData = transformData( + data, + ({ value, displayValue, label }) => { + if (!Array.isArray(value)) { + return { value, displayValue, label } + } + } + ) + }) + + render( + + + + + + ) + + fireEvent.submit(document.querySelector('form')) + + expect(onSubmit).toHaveBeenCalledTimes(1) + expect(transformedData).toEqual({ + accounts: [ + { + fooPath: { + displayValue: 'foo value', + label: 'Bar label', + value: 'foo value', + }, + }, + ], + }) + + const stringField = document.querySelector('input') + fireEvent.change(stringField, { target: { value: 'bar value' } }) + + fireEvent.submit(document.querySelector('form')) + + expect(onSubmit).toHaveBeenCalledTimes(2) + expect(transformedData).toEqual({ + accounts: [ + { + fooPath: { + displayValue: 'bar value', + label: 'Bar label', + value: 'bar value', + }, + }, + ], + }) + }) + describe('reduceToVisibleFields', () => { it('should remove data entries of hidden fields using Visibility', async () => { let submitData = null