Skip to content

Commit e5f28d6

Browse files
author
Ruben van Leeuwen
committed
1954: When calling getFormFieldValue defaults to own value if no fielName is passed
1 parent a43619f commit e5f28d6

File tree

2 files changed

+93
-14
lines changed

2 files changed

+93
-14
lines changed

frontend/packages/pydantic-forms/src/utils.spec.ts

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,14 @@ describe('getFormFieldValue', () => {
7070
it('gets the value by fieldName', () => {
7171
const field = getPydanticFormFieldDummy({ id: 'name' });
7272
const fieldName = 'name';
73-
const value = getFormFieldValue(fieldName, formValues, field);
73+
const value = getFormFieldValue(formValues, field, fieldName);
7474
expect(value).toBe('John Doe');
7575
});
7676

7777
it('returns undefined for unknown fields', () => {
7878
const field = getPydanticFormFieldDummy({ id: 'name' });
7979
const fieldName = 'UNKNOWN_FIELD';
80-
const value = getFormFieldValue(fieldName, formValues, field);
80+
const value = getFormFieldValue(formValues, field, fieldName);
8181
expect(value).toBe(undefined);
8282
});
8383

@@ -104,14 +104,14 @@ describe('getFormFieldValue', () => {
104104
const field = getPydanticFormFieldDummy({
105105
id: 'company.contactPersons.0.name',
106106
});
107-
const value = getFormFieldValue('age', complexValues, field);
107+
const value = getFormFieldValue(complexValues, field, 'age');
108108
expect(value).toEqual(25);
109109

110110
const field2 = getPydanticFormFieldDummy({
111111
id: 'company.contactPersons.1.name',
112112
});
113113

114-
const value2 = getFormFieldValue('licenses', complexValues, field2);
114+
const value2 = getFormFieldValue(complexValues, field2, 'licenses');
115115
expect(value2).toEqual(['C']);
116116
});
117117

@@ -129,40 +129,86 @@ describe('getFormFieldValue', () => {
129129
id: 'company.contactIds.0',
130130
});
131131
const valueFromFirstListElement = getFormFieldValue(
132-
'age',
133132
complexValues,
134133
firstListElementField,
134+
'age',
135135
);
136136
expect(valueFromFirstListElement).toEqual(30);
137137

138138
const secondListElementField = getPydanticFormFieldDummy({
139139
id: 'company.contactIds.1',
140140
});
141141
const valueFromSecondListElement = getFormFieldValue(
142-
'age',
143142
complexValues,
144143
secondListElementField,
144+
'age',
145145
);
146146
expect(valueFromSecondListElement).toEqual(30);
147147

148148
const nameElementField = getPydanticFormFieldDummy({
149149
id: 'company.name',
150150
});
151151
const valueFromNameElement = getFormFieldValue(
152-
'age',
153152
complexValues,
154153
nameElementField,
154+
'age',
155155
);
156156
expect(valueFromNameElement).toEqual(30);
157157

158158
const contactIdsElementField = getPydanticFormFieldDummy({
159159
id: 'company.contactIds',
160160
});
161161
const ownValue = getFormFieldValue(
162-
'contactIds',
163162
complexValues,
164163
contactIdsElementField,
164+
'contactIds',
165165
);
166166
expect(ownValue).toEqual(['123', '456']);
167167
});
168+
169+
it('gets its own value based on the pydanticform definition if no fieldName is provided', () => {
170+
const complexValues = {
171+
company: {
172+
name: 'John Deer',
173+
age: 30,
174+
contactIds: ['123', '456'],
175+
},
176+
age: 666,
177+
};
178+
179+
const companyField = getPydanticFormFieldDummy({
180+
id: 'company',
181+
});
182+
const valueFromCompanyElement = getFormFieldValue(
183+
complexValues,
184+
companyField,
185+
);
186+
expect(valueFromCompanyElement).toEqual({
187+
name: 'John Deer',
188+
age: 30,
189+
contactIds: ['123', '456'],
190+
});
191+
192+
const secondListElementField = getPydanticFormFieldDummy({
193+
id: 'company.contactIds.1',
194+
});
195+
196+
const valueFromSecondListElement = getFormFieldValue(
197+
complexValues,
198+
secondListElementField,
199+
);
200+
201+
expect(valueFromSecondListElement).toEqual(['123', '456']);
202+
203+
const firstListElementField = getPydanticFormFieldDummy({
204+
id: 'company.contactIds.0',
205+
});
206+
207+
const valueFromListElement = getFormFieldValue(
208+
complexValues,
209+
firstListElementField,
210+
);
211+
212+
expect(valueFromListElement).toEqual(['123', '456']);
213+
});
168214
});

frontend/packages/pydantic-forms/src/utils.ts

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,37 @@ export const itemizeArrayItem = (
9494
return itemize(item, itemId);
9595
};
9696

97+
/**
98+
* Determines how many parts to slice from the PydanticFormField's id.
99+
* If the last segment is a number we conclude it's an array item and it returns 2 (to slice off the index and the field name).
100+
* Otherwise, it returns 1 (to slice off just the field name).
101+
*/
102+
const getNumberOfPartsToSlice = (
103+
pydanticFormField: PydanticFormField,
104+
): number => {
105+
const pathSegments = pydanticFormField.id.split('.');
106+
const lastSegment = pathSegments[pathSegments.length - 1];
107+
return isNaN(Number(lastSegment)) ? 1 : 2;
108+
};
109+
110+
/**
111+
* Returns the field name extracted from the PydanticFormField's id.
112+
* If the id contains a dot return the last segment, if the last segment is an integer
113+
* indicating a position in an array, it will return the segment before that.
114+
*/
115+
const getFieldName = (pydanticFormField: PydanticFormField): string => {
116+
if (pydanticFormField.id.includes('.')) {
117+
const numberOfPartsToSlice = getNumberOfPartsToSlice(pydanticFormField);
118+
return (
119+
pydanticFormField.id
120+
.split('.')
121+
.slice(0, -(numberOfPartsToSlice - 1))
122+
.pop() || ''
123+
);
124+
}
125+
return pydanticFormField.id;
126+
};
127+
97128
/**
98129
* This functions returns a fields value but taking into account the position
99130
* of the field in any tree it might be in. For example when requesting the
@@ -102,15 +133,17 @@ export const itemizeArrayItem = (
102133
* fields on other levels
103134
* */
104135
export function getFormFieldValue(
105-
fieldName: string,
106136
formValues: FieldValues,
107137
pydanticFormField: PydanticFormField,
138+
fieldName?: string,
108139
) {
140+
const name = fieldName ? fieldName : getFieldName(pydanticFormField);
141+
109142
// Determine by the path if we are part of an array. If we are, we need to chop of one more element
110-
const pathSegments = pydanticFormField.id.split('.');
111-
const lastSegment = pathSegments[pathSegments.length - 1];
112-
const sliceParts = isNaN(Number(lastSegment)) ? 1 : 2;
113-
const pathToParent = pydanticFormField.id.split('.').slice(0, -sliceParts);
143+
const numberOfPartsToSlice = getNumberOfPartsToSlice(pydanticFormField);
144+
const pathToParent = pydanticFormField.id
145+
.split('.')
146+
.slice(0, -numberOfPartsToSlice);
114147
let current: FieldValues = { ...formValues };
115148

116149
for (const segment of pathToParent) {
@@ -123,5 +156,5 @@ export function getFormFieldValue(
123156
}
124157
}
125158

126-
return current?.[fieldName];
159+
return current?.[name];
127160
}

0 commit comments

Comments
 (0)