Skip to content

Commit 7d88453

Browse files
committed
dropdown: enable mutliple selection by default
* Adds support and default implementation for multiple selection * closes CERNDocumentServer/cds-rdm#628
1 parent bbeb569 commit 7d88453

File tree

2 files changed

+87
-2
lines changed

2 files changed

+87
-2
lines changed

src/lib/forms/SelectField.js

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ import { Form } from "semantic-ui-react";
1212
import { FeedbackLabel } from "../forms/FeedbackLabel";
1313

1414
export class SelectField extends Component {
15+
constructor(props) {
16+
super(props);
17+
this.state = {
18+
options: props.options || [],
19+
};
20+
}
21+
1522
renderError = (meta, initialValue, initialErrors, value, errors) => {
1623
const { error, fieldPath } = this.props;
1724
const computedError =
@@ -31,6 +38,23 @@ export class SelectField extends Component {
3138
);
3239
};
3340

41+
componentDidUpdate(prevProps) {
42+
if (prevProps.options !== this.props.options) {
43+
const nextOptions = this.props.options || [];
44+
this.setState((prevState) => {
45+
// Merge previous state options and new props options, de-duplicating by value
46+
const existing = prevState.options || [];
47+
const merged = [...existing];
48+
nextOptions.forEach((opt) => {
49+
if (!merged.some((o) => o.value === opt.value)) {
50+
merged.push(opt);
51+
}
52+
});
53+
return { options: merged };
54+
});
55+
}
56+
}
57+
3458
renderFormField = (formikProps) => {
3559
const {
3660
form: {
@@ -55,11 +79,42 @@ export class SelectField extends Component {
5579
multiple,
5680
disabled,
5781
required,
82+
allowAdditions,
5883
...uiProps
5984
} = cmpProps;
6085
const _defaultValue = multiple ? [] : "";
61-
const value = getIn(values, fieldPath, defaultValue || _defaultValue);
86+
console.log("defaultValue:", defaultValue);
87+
let value = getIn(values, fieldPath, defaultValue || _defaultValue);
88+
// Fix: for multiple selects, normalize empty string to empty array
89+
if (multiple && (value === "" || value === null || value === undefined)) {
90+
value = [];
91+
}
6292
const initialValue = getIn(initialValues, fieldPath, _defaultValue);
93+
let dropdownOptions = (this.state.options && this.state.options.length > 0 ? this.state.options : options) || [];
94+
95+
// Ensure that all currently selected values are present in the options list
96+
const ensureOptionPresent = (val) => {
97+
if (val === undefined || val === null || val === "") return;
98+
if (!dropdownOptions.some((opt) => opt.value === val)) {
99+
dropdownOptions = [
100+
...dropdownOptions,
101+
{ key: val, text: val, value: val },
102+
];
103+
}
104+
};
105+
106+
if (multiple) {
107+
if (Array.isArray(value)) {
108+
value.forEach((v) => ensureOptionPresent(v));
109+
} else {
110+
ensureOptionPresent(value);
111+
}
112+
} else {
113+
ensureOptionPresent(value);
114+
}
115+
console.log("SelectField fieldPath:", fieldPath);
116+
console.log("SelectField value:", value);
117+
console.log("SelectField options:", dropdownOptions);
63118
return (
64119
<Form.Dropdown
65120
fluid
@@ -83,12 +138,36 @@ export class SelectField extends Component {
83138
onAddItem={(event, data) => {
84139
if (onAddItem) {
85140
onAddItem({ event, data, formikProps });
141+
} else {
142+
const newValue = data.value;
143+
// Add the new option to the local options state (if not already present)
144+
this.setState((prevState) => {
145+
const prevOptions = prevState.options || [];
146+
if (prevOptions.some((opt) => opt.value === newValue)) {
147+
return null;
148+
}
149+
const newOption = { key: newValue, text: newValue, value: newValue };
150+
return { options: [...prevOptions, newOption] };
151+
});
152+
153+
// Update the Formik field value
154+
if (multiple) {
155+
const current = Array.isArray(value)
156+
? value
157+
: value === undefined || value === null || value === ""
158+
? []
159+
: [value];
160+
setFieldValue(fieldPath, [...current, newValue]);
161+
} else {
162+
setFieldValue(fieldPath, newValue);
163+
}
86164
}
87165
}}
88-
options={options}
166+
options={dropdownOptions}
89167
value={value}
90168
multiple={multiple}
91169
selectOnBlur={false}
170+
allowAdditions={allowAdditions}
92171
{...uiProps}
93172
/>
94173
);
@@ -120,6 +199,7 @@ SelectField.propTypes = {
120199
label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
121200
onChange: PropTypes.func,
122201
onAddItem: PropTypes.func,
202+
allowAdditions: PropTypes.bool,
123203
multiple: PropTypes.bool,
124204
helpText: PropTypes.string,
125205
required: PropTypes.bool,
@@ -137,4 +217,5 @@ SelectField.defaultProps = {
137217
helpText: undefined,
138218
required: false,
139219
disabled: false,
220+
allowAdditions: false,
140221
};

src/lib/forms/widgets/select/Dropdown.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class DropdownComponent extends Component {
3131
required,
3232
disabled,
3333
optimized,
34+
allowAdditions,
3435
} = this.props;
3536

3637
const helpText = helpTextProp ?? description;
@@ -54,6 +55,7 @@ class DropdownComponent extends Component {
5455
defaultValue={multiple ? [] : ""}
5556
helpText={helpText}
5657
optimized={optimized}
58+
allowAdditions={allowAdditions}
5759
/>
5860
);
5961
}
@@ -78,6 +80,7 @@ DropdownComponent.propTypes = {
7880
*/
7981
icon: PropTypes.string,
8082
optimized: PropTypes.bool,
83+
allowAdditions: PropTypes.bool,
8184
...fieldCommonProps,
8285
};
8386

@@ -88,6 +91,7 @@ DropdownComponent.defaultProps = {
8891
clearable: true,
8992
description: undefined,
9093
optimized: true,
94+
allowAdditions: false,
9195
};
9296

9397
export const Dropdown = showHideOverridableWithDynamicId(DropdownComponent);

0 commit comments

Comments
 (0)