diff --git a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/PushContainer/properties.mdx b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/PushContainer/properties.mdx
index f1664abf510..516cfa1f8b9 100644
--- a/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/PushContainer/properties.mdx
+++ b/packages/dnb-design-system-portal/src/docs/uilib/extensions/forms/Iterate/PushContainer/properties.mdx
@@ -5,12 +5,19 @@ hideInMenu: true
import TranslationsTable from 'dnb-design-system-portal/src/shared/parts/TranslationsTable'
import PropertiesTable from 'dnb-design-system-portal/src/shared/parts/PropertiesTable'
-import { PushContainerProperties } from '@dnb/eufemia/src/extensions/forms/Iterate/PushContainer/PushContainerDocs'
+import {
+ PushContainerProperties,
+ PushContainerEvents,
+} from '@dnb/eufemia/src/extensions/forms/Iterate/PushContainer/PushContainerDocs'
## Properties
+## Events
+
+
+
## Translations
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 4eef3be8333..325927e8339 100644
--- a/packages/dnb-eufemia/src/extensions/forms/DataContext/Provider/Provider.tsx
+++ b/packages/dnb-eufemia/src/extensions/forms/DataContext/Provider/Provider.tsx
@@ -303,6 +303,7 @@ export default function Provider(
// eslint-disable-next-line react-hooks/exhaustive-deps -- Avoid triggering code that should only run initially
}, [])
const internalDataRef = useRef(initialData)
+ const isEmptyDataRef = useRef(false)
// - Validator
const ajvValidatorRef = useRef()
@@ -658,8 +659,10 @@ export default function Provider(
) {
cacheRef.current.shared = sharedData.data
- if (internalDataRef.current === clearedData) {
- return clearedData as Data
+ if (isEmptyDataRef.current) {
+ return (
+ Array.isArray(internalDataRef.current) ? [] : clearedData
+ ) as Data
}
return {
@@ -682,10 +685,12 @@ export default function Provider(
? pointer.get(internalData, props.path)
: internalData
- const isEmptyDataRef = useRef(false)
const clearData = useCallback(() => {
isEmptyDataRef.current = true
- internalDataRef.current = (emptyData ?? clearedData) as Data
+ internalDataRef.current = ((typeof emptyData === 'function'
+ ? emptyData(internalDataRef.current)
+ : emptyData) ??
+ (Array.isArray(internalDataRef.current) ? [] : clearedData)) as Data
if (id) {
setSharedData?.(internalDataRef.current)
@@ -1002,7 +1007,6 @@ export default function Provider(
if (isolate) {
submitResult = await onCommit?.(internalDataRef.current, {
clearData,
- setData,
})
} else {
submitResult = await onSubmit()
@@ -1075,7 +1079,6 @@ export default function Provider(
setFormState,
setShowAllErrors,
setSubmitState,
- setData,
]
)
@@ -1490,9 +1493,3 @@ function useFormStatusBuffer(props: FormStatusBufferProps) {
}
export const clearedData = Object.freeze({})
-export const getClearedData = (mergeData?: Record) => {
- if (mergeData) {
- return Object.assign(clearedData, mergeData)
- }
- return clearedData
-}
diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/PushContainer/PushContainer.tsx b/packages/dnb-eufemia/src/extensions/forms/Iterate/PushContainer/PushContainer.tsx
index b11ea93dde0..a9050f987c8 100644
--- a/packages/dnb-eufemia/src/extensions/forms/Iterate/PushContainer/PushContainer.tsx
+++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/PushContainer/PushContainer.tsx
@@ -8,7 +8,7 @@ import EditContainer, { CancelButton, DoneButton } from '../EditContainer'
import IterateArray, { ContainerMode } from '../Array'
import OpenButton from './OpenButton'
import { Flex, HeightAnimation } from '../../../../components'
-import { Path } from '../../types'
+import { OnCommit, Path } from '../../types'
import { SpacingProps } from '../../../../shared/types'
import { useArrayLimit, useSwitchContainerMode } from '../hooks'
import Toolbar from '../Toolbar'
@@ -58,6 +58,11 @@ export type Props = {
*/
toolbar?: React.ReactNode
+ /**
+ * Will be called when the user clicks on the "Done" button.
+ */
+ onCommit?: OnCommit
+
/**
* The container contents.
*/
@@ -76,6 +81,7 @@ function PushContainer(props: AllProps) {
children,
openButton,
showOpenButtonWhen,
+ onCommit,
...rest
} = props
@@ -120,16 +126,31 @@ function PushContainer(props: AllProps) {
}
}, [dataProp, defaultDataProp, isolatedData])
+ const emptyData = useCallback(
+ (data: { pushContainerItems: unknown[] }) => {
+ const firstItem = data.pushContainerItems?.[0]
+ if (firstItem === null || typeof firstItem !== 'object') {
+ return {
+ ...isolatedData,
+ pushContainerItems: [null],
+ }
+ }
+ return defaultData
+ },
+ [defaultData, isolatedData]
+ )
+
return (
{
return moveValueToPath(path, [...entries, ...pushContainerItems])
}}
- onCommit={(data, { clearData, setData, preventCommit }) => {
+ onCommit={(data, options) => {
+ const { clearData, preventCommit } = options
if (hasReachedLimit) {
preventCommit()
setShowStatus(true)
@@ -137,13 +158,8 @@ function PushContainer(props: AllProps) {
setNextContainerMode('view')
switchContainerModeRef.current?.('view')
clearData()
- if (isolatedData) {
- setData({
- ...isolatedData,
- pushContainerItems: [clearedData],
- })
- }
}
+ onCommit?.(data, options)
}}
>
diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/PushContainer/PushContainerDocs.ts b/packages/dnb-eufemia/src/extensions/forms/Iterate/PushContainer/PushContainerDocs.ts
index e8f56900dd5..54ac7f6b155 100644
--- a/packages/dnb-eufemia/src/extensions/forms/Iterate/PushContainer/PushContainerDocs.ts
+++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/PushContainer/PushContainerDocs.ts
@@ -1,4 +1,5 @@
import { PropertiesTableProps } from '../../../../shared/types'
+import { IsolationEvents } from '../../Form/Isolation/IsolationDocs'
export const PushContainerProperties: PropertiesTableProps = {
path: {
@@ -58,4 +59,6 @@ export const PushContainerProperties: PropertiesTableProps = {
},
}
-export const PushContainerEvents: PropertiesTableProps = {}
+export const PushContainerEvents: PropertiesTableProps = {
+ onCommit: IsolationEvents.onCommit,
+}
diff --git a/packages/dnb-eufemia/src/extensions/forms/Iterate/PushContainer/__tests__/PushContainer.test.tsx b/packages/dnb-eufemia/src/extensions/forms/Iterate/PushContainer/__tests__/PushContainer.test.tsx
index 40f2d19207f..9a39718fdb1 100644
--- a/packages/dnb-eufemia/src/extensions/forms/Iterate/PushContainer/__tests__/PushContainer.test.tsx
+++ b/packages/dnb-eufemia/src/extensions/forms/Iterate/PushContainer/__tests__/PushContainer.test.tsx
@@ -1,10 +1,11 @@
-import React from 'react'
+import React, { useContext } from 'react'
import { render, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { Field, Form, Iterate } from '../../..'
-import nbNO from '../../../constants/locales/nb-NO'
import { Div } from '../../../../../elements'
+import DataContext from '../../../DataContext/Context'
+import nbNO from '../../../constants/locales/nb-NO'
const nb = nbNO['nb-NO']
describe('PushContainer', () => {
@@ -548,7 +549,7 @@ describe('PushContainer', () => {
)
})
- it('should keep the defaultValue after clearing', async () => {
+ it('should not show error message after clearing', async () => {
const onChange = jest.fn()
render(
@@ -643,6 +644,68 @@ describe('PushContainer', () => {
expect(document.querySelector('.dnb-form-status')).toBeNull()
})
})
+
+ it('should keep the defaultValue after clearing', async () => {
+ const onChange = jest.fn()
+ const onCommit = jest.fn()
+
+ let internalContext = null
+ const CollectInternalData = () => {
+ internalContext = useContext(DataContext)
+ return null
+ }
+
+ render(
+
+
+
+
+
+
+ )
+
+ expect(internalContext).toMatchObject({
+ data: {
+ pushContainerItems: ['default value'],
+ },
+ })
+
+ const input = document.querySelector('input')
+
+ await userEvent.type(input, ' changed')
+
+ const button = document.querySelector('button')
+
+ await userEvent.click(button)
+ expect(internalContext.internalDataRef.current).toEqual({
+ pushContainerItems: ['default value'],
+ })
+ expect(onChange).toHaveBeenCalledTimes(1)
+ expect(onChange).toHaveBeenLastCalledWith(
+ ['default value changed'],
+ expect.anything()
+ )
+ expect(onCommit).toHaveBeenCalledTimes(1)
+ expect(onCommit).toHaveBeenLastCalledWith(
+ ['default value changed'],
+ expect.anything()
+ )
+
+ await userEvent.click(button)
+ expect(internalContext.internalDataRef.current).toEqual({
+ pushContainerItems: ['default value'],
+ })
+ expect(onChange).toHaveBeenCalledTimes(2)
+ expect(onChange).toHaveBeenLastCalledWith(
+ ['default value changed', 'default value'],
+ expect.anything()
+ )
+ expect(onCommit).toHaveBeenCalledTimes(2)
+ expect(onCommit).toHaveBeenLastCalledWith(
+ ['default value changed', 'default value'],
+ expect.anything()
+ )
+ })
})
it('should support initial data as a string', async () => {
diff --git a/packages/dnb-eufemia/src/extensions/forms/hooks/useFieldProps.ts b/packages/dnb-eufemia/src/extensions/forms/hooks/useFieldProps.ts
index fb02d0138ef..973ebea13cd 100644
--- a/packages/dnb-eufemia/src/extensions/forms/hooks/useFieldProps.ts
+++ b/packages/dnb-eufemia/src/extensions/forms/hooks/useFieldProps.ts
@@ -1823,11 +1823,8 @@ export default function useFieldProps(
useEffect(() => {
if (isEmptyData()) {
- // Fill the data context with the default value after it has been cleared
- requestAnimationFrame(() => {
- setContextData()
- validateValue()
- })
+ setContextData()
+ validateValue()
}
}, [isEmptyData, setContextData, validateValue])
diff --git a/packages/dnb-eufemia/src/extensions/forms/types.ts b/packages/dnb-eufemia/src/extensions/forms/types.ts
index c84c6a1606d..6ec8f27a635 100644
--- a/packages/dnb-eufemia/src/extensions/forms/types.ts
+++ b/packages/dnb-eufemia/src/extensions/forms/types.ts
@@ -602,7 +602,6 @@ export type OnCommit = (
preventCommit,
}: {
clearData: () => void
- setData?: (data: Data) => void
preventCommit?: () => void
}
) =>