diff --git a/src/features/formData/FormData.test.tsx b/src/features/formData/FormData.test.tsx
index d8d0276dcc..5bde53479c 100644
--- a/src/features/formData/FormData.test.tsx
+++ b/src/features/formData/FormData.test.tsx
@@ -21,6 +21,7 @@ import { RulesProvider } from 'src/features/form/rules/RulesContext';
import { GlobalFormDataReadersProvider } from 'src/features/formData/FormDataReaders';
import { FD, FormDataWriteProvider } from 'src/features/formData/FormDataWrite';
import { FormDataWriteProxyProvider } from 'src/features/formData/FormDataWriteProxies';
+import { DEFAULT_DEBOUNCE_TIMEOUT } from 'src/features/formData/types';
import { useDataModelBindings } from 'src/features/formData/useDataModelBindings';
import { fetchApplicationMetadata } from 'src/queries/queries';
import {
@@ -753,4 +754,63 @@ describe('FormData', () => {
expect(screen.getByTestId('valid-obj3.prop1')).toHaveValue('');
});
});
+
+ // Regression test for https://github.com/Altinn/app-frontend-react/issues/4053
+ describe('List data model bindings regression, issue #4053', () => {
+ const listSchema: JSONSchema7 = {
+ type: 'object',
+ properties: {
+ designs: {
+ type: 'array',
+ items: {
+ type: 'object',
+ properties: {
+ attachmentId: {
+ type: 'array',
+ items: { type: 'string' },
+ },
+ },
+ },
+ },
+ },
+ };
+
+ function ListWriter() {
+ const { formData, setValue } = useDataModelBindings(
+ { list: { field: 'designs[0].attachmentId', dataType: defaultDataTypeMock } },
+ DEFAULT_DEBOUNCE_TIMEOUT,
+ 'raw',
+ );
+ const list = (formData.list ?? []) as string[];
+
+ return (
+ <>
+
{list.join(',')}
+
+ >
+ );
+ }
+
+ async function render() {
+ return statefulRender({
+ renderer: ,
+ queries: {
+ fetchDataModelSchema: async () => listSchema,
+ fetchFormData: async () => ({ designs: [{ attachmentId: ['id-1', 'id-2'] }] }),
+ },
+ });
+ }
+
+ it('writing a list binding that is already pre-populated with 2+ values should not throw', async () => {
+ const user = userEvent.setup();
+ await render();
+ expect(screen.getByTestId('list-value')).toHaveTextContent('id-1,id-2');
+ // This is what MaintainListDataModelBinding does on load when the order of the mapped
+ // attachments differs from the order stored in the data model. Before the fix this throws
+ // "Trying to redefine non-empty obj['attachmentId']".
+ await user.click(screen.getByRole('button', { name: 'Update list' }));
+
+ await waitFor(() => expect(screen.getByTestId('list-value')).toHaveTextContent('id-2,id-1'));
+ });
+ });
});
diff --git a/src/features/formData/FormDataWriteStateMachine.tsx b/src/features/formData/FormDataWriteStateMachine.tsx
index 22a5bf11c9..1e959c8bb3 100644
--- a/src/features/formData/FormDataWriteStateMachine.tsx
+++ b/src/features/formData/FormDataWriteStateMachine.tsx
@@ -367,6 +367,7 @@ function makeActions(
dot.str(reference.field, newValue, state.dataModels[reference.dataType].invalidCurrentData);
} else {
dot.delete(reference.field, state.dataModels[reference.dataType].invalidCurrentData);
+ dot.delete(reference.field, state.dataModels[reference.dataType].currentData);
dot.str(reference.field, convertedValue, state.dataModels[reference.dataType].currentData);
}
return { newValue, convertedValue, error, hadError };