@formio/js 5.0.0-dev.5933.606556f → 5.0.0-dev.5936.905c79f
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/formio.form.js +4 -4
- package/dist/formio.form.min.js +1 -1
- package/dist/formio.full.js +5 -5
- package/dist/formio.full.min.js +1 -1
- package/lib/cjs/WebformBuilder.js +7 -0
- package/lib/cjs/Wizard.js +11 -9
- package/lib/cjs/components/datagrid/DataGrid.js +0 -4
- package/lib/cjs/components/radio/Radio.d.ts +4 -0
- package/lib/cjs/components/radio/Radio.js +66 -23
- package/lib/cjs/components/selectboxes/SelectBoxes.js +8 -0
- package/lib/mjs/WebformBuilder.js +7 -0
- package/lib/mjs/Wizard.js +11 -9
- package/lib/mjs/components/datagrid/DataGrid.js +0 -4
- package/lib/mjs/components/radio/Radio.d.ts +4 -0
- package/lib/mjs/components/radio/Radio.js +66 -23
- package/lib/mjs/components/selectboxes/SelectBoxes.js +8 -0
- package/package.json +1 -1
|
@@ -1085,6 +1085,12 @@ class WebformBuilder extends Component_1.default {
|
|
|
1085
1085
|
parentComponent.tabs[tabIndex].splice(index, 1, newComp);
|
|
1086
1086
|
newComp.checkValidity = () => true;
|
|
1087
1087
|
newComp.build(defaultValueComponent.element);
|
|
1088
|
+
if (this.preview && !this.preview.defaultChanged) {
|
|
1089
|
+
const defaultValue = lodash_1.default.get(this.preview._data, this.editForm._data.key);
|
|
1090
|
+
if (lodash_1.default.isObject(defaultValue) && !lodash_1.default.isArray(defaultValue)) {
|
|
1091
|
+
this.editForm._data.defaultValue = defaultValue;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1088
1094
|
}
|
|
1089
1095
|
}
|
|
1090
1096
|
else {
|
|
@@ -1095,6 +1101,7 @@ class WebformBuilder extends Component_1.default {
|
|
|
1095
1101
|
path.unshift(component.key);
|
|
1096
1102
|
dataPath = (0, utils_1.getStringFromComponentPath)(path);
|
|
1097
1103
|
}
|
|
1104
|
+
this.preview.defaultChanged = true;
|
|
1098
1105
|
lodash_1.default.set(this.preview._data, dataPath, changed.value);
|
|
1099
1106
|
lodash_1.default.set(this.webform._data, dataPath, changed.value);
|
|
1100
1107
|
}
|
package/lib/cjs/Wizard.js
CHANGED
|
@@ -602,7 +602,10 @@ class Wizard extends Webform_1.default {
|
|
|
602
602
|
}
|
|
603
603
|
this.redraw().then(() => {
|
|
604
604
|
this.checkData(this.submission.data);
|
|
605
|
-
this.validateCurrentPage();
|
|
605
|
+
const errors = this.submitted ? this.validate(this.localData, { dirty: true }) : this.validateCurrentPage();
|
|
606
|
+
if (this.alert) {
|
|
607
|
+
this.showErrors(errors, true, true);
|
|
608
|
+
}
|
|
606
609
|
});
|
|
607
610
|
return Promise.resolve();
|
|
608
611
|
}
|
|
@@ -699,9 +702,11 @@ class Wizard extends Webform_1.default {
|
|
|
699
702
|
});
|
|
700
703
|
});
|
|
701
704
|
}
|
|
702
|
-
// Validate the form
|
|
703
|
-
const
|
|
704
|
-
|
|
705
|
+
// Validate the form before going to the next page
|
|
706
|
+
const currentPageErrors = this.validateCurrentPage({ dirty: true });
|
|
707
|
+
const errors = this.submitted ? this.validate(this.localData, { dirty: true }) : currentPageErrors;
|
|
708
|
+
// allow going to the next page if the current page is valid, even if there are form level errors
|
|
709
|
+
if (currentPageErrors.length === 0) {
|
|
705
710
|
this.checkData(this.submission.data);
|
|
706
711
|
return this.beforePage(true).then(() => {
|
|
707
712
|
return this.setPage(this.getNextPage()).then(() => {
|
|
@@ -716,7 +721,7 @@ class Wizard extends Webform_1.default {
|
|
|
716
721
|
else {
|
|
717
722
|
this.currentPage.components.forEach((comp) => comp.setPristine(false));
|
|
718
723
|
this.scrollIntoView(this.element, true);
|
|
719
|
-
return Promise.reject(
|
|
724
|
+
return Promise.reject(this.showErrors(errors, true));
|
|
720
725
|
}
|
|
721
726
|
}
|
|
722
727
|
validateCurrentPage(flags = {}) {
|
|
@@ -921,10 +926,7 @@ class Wizard extends Webform_1.default {
|
|
|
921
926
|
return components.reduce((check, comp) => comp.checkValidity(data, dirty, row, currentPageOnly, childErrors) && check, true);
|
|
922
927
|
}
|
|
923
928
|
get errors() {
|
|
924
|
-
|
|
925
|
-
return this.currentPage.errors;
|
|
926
|
-
}
|
|
927
|
-
return super.errors;
|
|
929
|
+
return !this.isLastPage() && !this.submitted ? this.currentPage.errors : super.errors;
|
|
928
930
|
}
|
|
929
931
|
focusOnComponent(key) {
|
|
930
932
|
const component = this.getComponent(key);
|
|
@@ -413,7 +413,6 @@ class DataGridComponent extends NestedArrayComponent_1.default {
|
|
|
413
413
|
});
|
|
414
414
|
this.checkConditions();
|
|
415
415
|
this.triggerChange();
|
|
416
|
-
this.triggerChange({ modified: true });
|
|
417
416
|
this.redraw().then(() => {
|
|
418
417
|
this.focusOnNewRowElement(this.rows[index]);
|
|
419
418
|
});
|
|
@@ -493,9 +492,6 @@ class DataGridComponent extends NestedArrayComponent_1.default {
|
|
|
493
492
|
const options = lodash_1.default.clone(this.options);
|
|
494
493
|
options.name += `[${rowIndex}]`;
|
|
495
494
|
options.row = `${rowIndex}-${colIndex}`;
|
|
496
|
-
options.onChange = (flags, changed, modified) => {
|
|
497
|
-
this.triggerChange({ modified });
|
|
498
|
-
};
|
|
499
495
|
let columnComponent;
|
|
500
496
|
if (this.builderMode) {
|
|
501
497
|
col.id = col.id + rowIndex;
|
|
@@ -27,6 +27,7 @@ export default class RadioComponent extends ListComponent {
|
|
|
27
27
|
itemsLoadedResolve: ((value: any) => void) | undefined;
|
|
28
28
|
optionsLoaded: boolean | undefined;
|
|
29
29
|
loadedOptions: any[] | undefined;
|
|
30
|
+
valuesMap: Map<any, any> | undefined;
|
|
30
31
|
beforeSubmit(): Promise<any>;
|
|
31
32
|
render(): import("../_classes/field/Field").default;
|
|
32
33
|
attach(element: any): Promise<void>;
|
|
@@ -35,10 +36,13 @@ export default class RadioComponent extends ListComponent {
|
|
|
35
36
|
validateValueAvailability(setting: any, value: any): boolean;
|
|
36
37
|
getValueAsString(value: any, options?: {}): any;
|
|
37
38
|
setValueAt(index: any, value: any): void;
|
|
39
|
+
prepareValue(item: any, options?: {}): any;
|
|
40
|
+
getValueByInput(input: any): any;
|
|
38
41
|
loadItems(url: any, search: any, headers: any, options: any, method: any, body: any): void;
|
|
39
42
|
loadItemsFromMetadata(): void;
|
|
40
43
|
setItems(items: any): void;
|
|
41
44
|
setSelectedClasses(): void;
|
|
45
|
+
setMetadata(value: any): void;
|
|
42
46
|
updateValue(value: any, flags: any): boolean;
|
|
43
47
|
currentValue: any;
|
|
44
48
|
}
|
|
@@ -7,6 +7,7 @@ const lodash_1 = __importDefault(require("lodash"));
|
|
|
7
7
|
const ListComponent_1 = __importDefault(require("../_classes/list/ListComponent"));
|
|
8
8
|
const Formio_1 = require("../../Formio");
|
|
9
9
|
const utils_1 = require("../../utils/utils");
|
|
10
|
+
const uuid_1 = require("uuid");
|
|
10
11
|
class RadioComponent extends ListComponent_1.default {
|
|
11
12
|
static schema(...extend) {
|
|
12
13
|
return ListComponent_1.default.schema({
|
|
@@ -142,6 +143,7 @@ class RadioComponent extends ListComponent_1.default {
|
|
|
142
143
|
});
|
|
143
144
|
this.optionsLoaded = !this.component.dataSrc || this.component.dataSrc === 'values';
|
|
144
145
|
this.loadedOptions = [];
|
|
146
|
+
this.valuesMap = new Map();
|
|
145
147
|
if (!this.visible) {
|
|
146
148
|
this.itemsLoadedResolve();
|
|
147
149
|
}
|
|
@@ -181,9 +183,12 @@ class RadioComponent extends ListComponent_1.default {
|
|
|
181
183
|
if (!lodash_1.default.isString(this.dataValue)) {
|
|
182
184
|
dataValue = lodash_1.default.toString(this.dataValue);
|
|
183
185
|
}
|
|
184
|
-
if (this.isSelectURL
|
|
185
|
-
const
|
|
186
|
-
|
|
186
|
+
if (this.isSelectURL) {
|
|
187
|
+
const valueKey = this.loadedOptions[index].value;
|
|
188
|
+
const optionValue = this.valuesMap.has(valueKey)
|
|
189
|
+
? this.valuesMap.get(valueKey)
|
|
190
|
+
: valueKey;
|
|
191
|
+
input.checked = lodash_1.default.isEqual(this.normalizeValue(optionValue), this.dataValue);
|
|
187
192
|
}
|
|
188
193
|
else {
|
|
189
194
|
input.checked = (dataValue === input.value && (input.value || this.component.dataSrc !== 'url'));
|
|
@@ -220,9 +225,14 @@ class RadioComponent extends ListComponent_1.default {
|
|
|
220
225
|
let value = this.component.inputType === 'checkbox' ? '' : this.dataValue;
|
|
221
226
|
this.refs.input.forEach((input, index) => {
|
|
222
227
|
if (input.checked) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
228
|
+
if (!this.isSelectURL) {
|
|
229
|
+
value = input.value;
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const optionValue = this.loadedOptions[index].value;
|
|
233
|
+
value = this.valuesMap.has(optionValue)
|
|
234
|
+
? this.valuesMap.get(optionValue)
|
|
235
|
+
: optionValue;
|
|
226
236
|
}
|
|
227
237
|
});
|
|
228
238
|
return value;
|
|
@@ -266,8 +276,8 @@ class RadioComponent extends ListComponent_1.default {
|
|
|
266
276
|
}
|
|
267
277
|
setValueAt(index, value) {
|
|
268
278
|
if (this.refs.input && this.refs.input[index] && value !== null && value !== undefined) {
|
|
269
|
-
const inputValue = this.refs.input[index]
|
|
270
|
-
this.refs.input[index].checked = (inputValue
|
|
279
|
+
const inputValue = this.getValueByInput(this.refs.input[index]);
|
|
280
|
+
this.refs.input[index].checked = lodash_1.default.isEqual(inputValue, value);
|
|
271
281
|
}
|
|
272
282
|
}
|
|
273
283
|
get shouldLoad() {
|
|
@@ -277,6 +287,23 @@ class RadioComponent extends ListComponent_1.default {
|
|
|
277
287
|
}
|
|
278
288
|
return super.shouldLoad;
|
|
279
289
|
}
|
|
290
|
+
prepareValue(item, options = {}) {
|
|
291
|
+
const value = this.component.valueProperty && !options.skipValueProperty
|
|
292
|
+
? lodash_1.default.get(item, this.component.valueProperty)
|
|
293
|
+
: item;
|
|
294
|
+
if (this.component.type === 'radio' && typeof value !== 'string') {
|
|
295
|
+
const uuid = (0, uuid_1.v4)();
|
|
296
|
+
this.valuesMap.set(uuid, value);
|
|
297
|
+
return uuid;
|
|
298
|
+
}
|
|
299
|
+
return value;
|
|
300
|
+
}
|
|
301
|
+
getValueByInput(input) {
|
|
302
|
+
const inputValue = input.value;
|
|
303
|
+
return this.valuesMap.has(inputValue)
|
|
304
|
+
? this.valuesMap.get(inputValue)
|
|
305
|
+
: inputValue;
|
|
306
|
+
}
|
|
280
307
|
loadItems(url, search, headers, options, method, body) {
|
|
281
308
|
if (this.optionsLoaded) {
|
|
282
309
|
this.itemsLoadedResolve();
|
|
@@ -327,7 +354,7 @@ class RadioComponent extends ListComponent_1.default {
|
|
|
327
354
|
label: this.itemTemplate(item)
|
|
328
355
|
};
|
|
329
356
|
if (lodash_1.default.isEqual(item, this.selectData || lodash_1.default.pick(this.dataValue, lodash_1.default.keys(item)))) {
|
|
330
|
-
this.loadedOptions[i].value = this.dataValue;
|
|
357
|
+
this.loadedOptions[i].value = this.prepareValue(this.dataValue, { skipValueProperty: true });
|
|
331
358
|
}
|
|
332
359
|
});
|
|
333
360
|
this.optionsLoaded = true;
|
|
@@ -337,12 +364,15 @@ class RadioComponent extends ListComponent_1.default {
|
|
|
337
364
|
const listData = [];
|
|
338
365
|
items === null || items === void 0 ? void 0 : items.forEach((item, i) => {
|
|
339
366
|
const valueAtProperty = lodash_1.default.get(item, this.component.valueProperty);
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
367
|
+
const value = this.prepareValue(item);
|
|
368
|
+
const label = this.component.valueProperty
|
|
369
|
+
? this.itemTemplate(item, valueAtProperty, i)
|
|
370
|
+
: this.itemTemplate(item, item, i);
|
|
371
|
+
this.loadedOptions[i] = { label, value };
|
|
372
|
+
listData.push(this.templateData[i]);
|
|
373
|
+
if (this.valuesMap.has(value)) {
|
|
374
|
+
this.templateData[value] = this.templateData[i];
|
|
375
|
+
}
|
|
346
376
|
if (!this.isRadio && (lodash_1.default.isObject(value) || lodash_1.default.isBoolean(value) || lodash_1.default.isUndefined(value))) {
|
|
347
377
|
this.loadedOptions[i].invalid = true;
|
|
348
378
|
}
|
|
@@ -365,7 +395,9 @@ class RadioComponent extends ListComponent_1.default {
|
|
|
365
395
|
const value = this.dataValue;
|
|
366
396
|
this.refs.wrapper.forEach((wrapper, index) => {
|
|
367
397
|
const input = this.refs.input[index];
|
|
368
|
-
const checked = (input.type === 'checkbox')
|
|
398
|
+
const checked = (input.type === 'checkbox')
|
|
399
|
+
? value[input.value] || input.checked
|
|
400
|
+
: lodash_1.default.isEqual(this.normalizeValue(this.getValueByInput(input)), value);
|
|
369
401
|
if (checked) {
|
|
370
402
|
//add class to container when selected
|
|
371
403
|
this.addClass(wrapper, this.optionSelectedClass);
|
|
@@ -379,10 +411,25 @@ class RadioComponent extends ListComponent_1.default {
|
|
|
379
411
|
});
|
|
380
412
|
}
|
|
381
413
|
}
|
|
414
|
+
setMetadata(value) {
|
|
415
|
+
let key = value;
|
|
416
|
+
if (typeof value !== 'string') {
|
|
417
|
+
const checkedInput = Array.prototype.find.call(this.refs.input, (input => input.type === 'radio' && input.getAttribute('checked')));
|
|
418
|
+
key = (checkedInput === null || checkedInput === void 0 ? void 0 : checkedInput.value) || key;
|
|
419
|
+
}
|
|
420
|
+
if (this.isSelectURL && this.templateData && this.templateData[key]) {
|
|
421
|
+
const submission = this.root.submission;
|
|
422
|
+
if (!submission.metadata.selectData) {
|
|
423
|
+
submission.metadata.selectData = {};
|
|
424
|
+
}
|
|
425
|
+
lodash_1.default.set(submission.metadata.selectData, this.path, this.templateData[key]);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
382
428
|
updateValue(value, flags) {
|
|
383
429
|
const changed = super.updateValue(value, flags);
|
|
384
430
|
if (changed) {
|
|
385
431
|
this.setSelectedClasses();
|
|
432
|
+
this.setMetadata(this.dataValue);
|
|
386
433
|
}
|
|
387
434
|
if (!flags || !flags.modified || !this.isRadio) {
|
|
388
435
|
if (changed) {
|
|
@@ -438,14 +485,10 @@ class RadioComponent extends ListComponent_1.default {
|
|
|
438
485
|
value = !(!value || value.toString() === 'false');
|
|
439
486
|
break;
|
|
440
487
|
}
|
|
441
|
-
if (this.isSelectURL && this.templateData && this.templateData[value]) {
|
|
442
|
-
const submission = this.root.submission;
|
|
443
|
-
if (!submission.metadata.selectData) {
|
|
444
|
-
submission.metadata.selectData = {};
|
|
445
|
-
}
|
|
446
|
-
lodash_1.default.set(submission.metadata.selectData, this.path, this.templateData[value]);
|
|
447
|
-
}
|
|
448
488
|
return super.normalizeValue(value);
|
|
449
489
|
}
|
|
490
|
+
isSingleInputValue() {
|
|
491
|
+
return true;
|
|
492
|
+
}
|
|
450
493
|
}
|
|
451
494
|
exports.default = RadioComponent;
|
|
@@ -139,6 +139,14 @@ class SelectBoxesComponent extends Radio_1.default {
|
|
|
139
139
|
checkedValues.forEach((value) => selectData.push(this.templateData[value]));
|
|
140
140
|
lodash_1.default.set(submission.metadata.selectData, this.path, selectData);
|
|
141
141
|
}
|
|
142
|
+
// Ensure that for dataSrc == 'values' that there are not any other superfluous values.
|
|
143
|
+
if (this.component.dataSrc === 'values') {
|
|
144
|
+
for (const key in value) {
|
|
145
|
+
if (!this.component.values.find((val) => val.value === key)) {
|
|
146
|
+
delete value[key];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
142
150
|
return value;
|
|
143
151
|
}
|
|
144
152
|
/**
|
|
@@ -1069,6 +1069,12 @@ export default class WebformBuilder extends Component {
|
|
|
1069
1069
|
parentComponent.tabs[tabIndex].splice(index, 1, newComp);
|
|
1070
1070
|
newComp.checkValidity = () => true;
|
|
1071
1071
|
newComp.build(defaultValueComponent.element);
|
|
1072
|
+
if (this.preview && !this.preview.defaultChanged) {
|
|
1073
|
+
const defaultValue = _.get(this.preview._data, this.editForm._data.key);
|
|
1074
|
+
if (_.isObject(defaultValue) && !_.isArray(defaultValue)) {
|
|
1075
|
+
this.editForm._data.defaultValue = defaultValue;
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1072
1078
|
}
|
|
1073
1079
|
}
|
|
1074
1080
|
else {
|
|
@@ -1079,6 +1085,7 @@ export default class WebformBuilder extends Component {
|
|
|
1079
1085
|
path.unshift(component.key);
|
|
1080
1086
|
dataPath = getStringFromComponentPath(path);
|
|
1081
1087
|
}
|
|
1088
|
+
this.preview.defaultChanged = true;
|
|
1082
1089
|
_.set(this.preview._data, dataPath, changed.value);
|
|
1083
1090
|
_.set(this.webform._data, dataPath, changed.value);
|
|
1084
1091
|
}
|
package/lib/mjs/Wizard.js
CHANGED
|
@@ -594,7 +594,10 @@ export default class Wizard extends Webform {
|
|
|
594
594
|
}
|
|
595
595
|
this.redraw().then(() => {
|
|
596
596
|
this.checkData(this.submission.data);
|
|
597
|
-
this.validateCurrentPage();
|
|
597
|
+
const errors = this.submitted ? this.validate(this.localData, { dirty: true }) : this.validateCurrentPage();
|
|
598
|
+
if (this.alert) {
|
|
599
|
+
this.showErrors(errors, true, true);
|
|
600
|
+
}
|
|
598
601
|
});
|
|
599
602
|
return Promise.resolve();
|
|
600
603
|
}
|
|
@@ -689,9 +692,11 @@ export default class Wizard extends Webform {
|
|
|
689
692
|
});
|
|
690
693
|
});
|
|
691
694
|
}
|
|
692
|
-
// Validate the form
|
|
693
|
-
const
|
|
694
|
-
|
|
695
|
+
// Validate the form before going to the next page
|
|
696
|
+
const currentPageErrors = this.validateCurrentPage({ dirty: true });
|
|
697
|
+
const errors = this.submitted ? this.validate(this.localData, { dirty: true }) : currentPageErrors;
|
|
698
|
+
// allow going to the next page if the current page is valid, even if there are form level errors
|
|
699
|
+
if (currentPageErrors.length === 0) {
|
|
695
700
|
this.checkData(this.submission.data);
|
|
696
701
|
return this.beforePage(true).then(() => {
|
|
697
702
|
return this.setPage(this.getNextPage()).then(() => {
|
|
@@ -706,7 +711,7 @@ export default class Wizard extends Webform {
|
|
|
706
711
|
else {
|
|
707
712
|
this.currentPage.components.forEach((comp) => comp.setPristine(false));
|
|
708
713
|
this.scrollIntoView(this.element, true);
|
|
709
|
-
return Promise.reject(
|
|
714
|
+
return Promise.reject(this.showErrors(errors, true));
|
|
710
715
|
}
|
|
711
716
|
}
|
|
712
717
|
validateCurrentPage(flags = {}) {
|
|
@@ -908,10 +913,7 @@ export default class Wizard extends Webform {
|
|
|
908
913
|
return components.reduce((check, comp) => comp.checkValidity(data, dirty, row, currentPageOnly, childErrors) && check, true);
|
|
909
914
|
}
|
|
910
915
|
get errors() {
|
|
911
|
-
|
|
912
|
-
return this.currentPage.errors;
|
|
913
|
-
}
|
|
914
|
-
return super.errors;
|
|
916
|
+
return !this.isLastPage() && !this.submitted ? this.currentPage.errors : super.errors;
|
|
915
917
|
}
|
|
916
918
|
focusOnComponent(key) {
|
|
917
919
|
const component = this.getComponent(key);
|
|
@@ -410,7 +410,6 @@ export default class DataGridComponent extends NestedArrayComponent {
|
|
|
410
410
|
});
|
|
411
411
|
this.checkConditions();
|
|
412
412
|
this.triggerChange();
|
|
413
|
-
this.triggerChange({ modified: true });
|
|
414
413
|
this.redraw().then(() => {
|
|
415
414
|
this.focusOnNewRowElement(this.rows[index]);
|
|
416
415
|
});
|
|
@@ -489,9 +488,6 @@ export default class DataGridComponent extends NestedArrayComponent {
|
|
|
489
488
|
const options = _.clone(this.options);
|
|
490
489
|
options.name += `[${rowIndex}]`;
|
|
491
490
|
options.row = `${rowIndex}-${colIndex}`;
|
|
492
|
-
options.onChange = (flags, changed, modified) => {
|
|
493
|
-
this.triggerChange({ modified });
|
|
494
|
-
};
|
|
495
491
|
let columnComponent;
|
|
496
492
|
if (this.builderMode) {
|
|
497
493
|
col.id = col.id + rowIndex;
|
|
@@ -27,6 +27,7 @@ export default class RadioComponent extends ListComponent {
|
|
|
27
27
|
itemsLoadedResolve: ((value: any) => void) | undefined;
|
|
28
28
|
optionsLoaded: boolean | undefined;
|
|
29
29
|
loadedOptions: any[] | undefined;
|
|
30
|
+
valuesMap: Map<any, any> | undefined;
|
|
30
31
|
beforeSubmit(): Promise<any>;
|
|
31
32
|
render(): import("../_classes/field/Field").default;
|
|
32
33
|
attach(element: any): Promise<void>;
|
|
@@ -35,10 +36,13 @@ export default class RadioComponent extends ListComponent {
|
|
|
35
36
|
validateValueAvailability(setting: any, value: any): boolean;
|
|
36
37
|
getValueAsString(value: any, options?: {}): any;
|
|
37
38
|
setValueAt(index: any, value: any): void;
|
|
39
|
+
prepareValue(item: any, options?: {}): any;
|
|
40
|
+
getValueByInput(input: any): any;
|
|
38
41
|
loadItems(url: any, search: any, headers: any, options: any, method: any, body: any): void;
|
|
39
42
|
loadItemsFromMetadata(): void;
|
|
40
43
|
setItems(items: any): void;
|
|
41
44
|
setSelectedClasses(): void;
|
|
45
|
+
setMetadata(value: any): void;
|
|
42
46
|
updateValue(value: any, flags: any): boolean;
|
|
43
47
|
currentValue: any;
|
|
44
48
|
}
|
|
@@ -2,6 +2,7 @@ import _ from 'lodash';
|
|
|
2
2
|
import ListComponent from '../_classes/list/ListComponent';
|
|
3
3
|
import { Formio } from '../../Formio';
|
|
4
4
|
import { boolValue, componentValueTypes, getComponentSavedTypes } from '../../utils/utils';
|
|
5
|
+
import { v4 as uuidv4 } from 'uuid';
|
|
5
6
|
export default class RadioComponent extends ListComponent {
|
|
6
7
|
static schema(...extend) {
|
|
7
8
|
return ListComponent.schema({
|
|
@@ -142,6 +143,7 @@ export default class RadioComponent extends ListComponent {
|
|
|
142
143
|
});
|
|
143
144
|
this.optionsLoaded = !this.component.dataSrc || this.component.dataSrc === 'values';
|
|
144
145
|
this.loadedOptions = [];
|
|
146
|
+
this.valuesMap = new Map();
|
|
145
147
|
if (!this.visible) {
|
|
146
148
|
this.itemsLoadedResolve();
|
|
147
149
|
}
|
|
@@ -181,9 +183,12 @@ export default class RadioComponent extends ListComponent {
|
|
|
181
183
|
if (!_.isString(this.dataValue)) {
|
|
182
184
|
dataValue = _.toString(this.dataValue);
|
|
183
185
|
}
|
|
184
|
-
if (this.isSelectURL
|
|
185
|
-
const
|
|
186
|
-
|
|
186
|
+
if (this.isSelectURL) {
|
|
187
|
+
const valueKey = this.loadedOptions[index].value;
|
|
188
|
+
const optionValue = this.valuesMap.has(valueKey)
|
|
189
|
+
? this.valuesMap.get(valueKey)
|
|
190
|
+
: valueKey;
|
|
191
|
+
input.checked = _.isEqual(this.normalizeValue(optionValue), this.dataValue);
|
|
187
192
|
}
|
|
188
193
|
else {
|
|
189
194
|
input.checked = (dataValue === input.value && (input.value || this.component.dataSrc !== 'url'));
|
|
@@ -220,9 +225,14 @@ export default class RadioComponent extends ListComponent {
|
|
|
220
225
|
let value = this.component.inputType === 'checkbox' ? '' : this.dataValue;
|
|
221
226
|
this.refs.input.forEach((input, index) => {
|
|
222
227
|
if (input.checked) {
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
228
|
+
if (!this.isSelectURL) {
|
|
229
|
+
value = input.value;
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const optionValue = this.loadedOptions[index].value;
|
|
233
|
+
value = this.valuesMap.has(optionValue)
|
|
234
|
+
? this.valuesMap.get(optionValue)
|
|
235
|
+
: optionValue;
|
|
226
236
|
}
|
|
227
237
|
});
|
|
228
238
|
return value;
|
|
@@ -266,8 +276,8 @@ export default class RadioComponent extends ListComponent {
|
|
|
266
276
|
}
|
|
267
277
|
setValueAt(index, value) {
|
|
268
278
|
if (this.refs.input && this.refs.input[index] && value !== null && value !== undefined) {
|
|
269
|
-
const inputValue = this.refs.input[index]
|
|
270
|
-
this.refs.input[index].checked = (inputValue
|
|
279
|
+
const inputValue = this.getValueByInput(this.refs.input[index]);
|
|
280
|
+
this.refs.input[index].checked = _.isEqual(inputValue, value);
|
|
271
281
|
}
|
|
272
282
|
}
|
|
273
283
|
get shouldLoad() {
|
|
@@ -277,6 +287,23 @@ export default class RadioComponent extends ListComponent {
|
|
|
277
287
|
}
|
|
278
288
|
return super.shouldLoad;
|
|
279
289
|
}
|
|
290
|
+
prepareValue(item, options = {}) {
|
|
291
|
+
const value = this.component.valueProperty && !options.skipValueProperty
|
|
292
|
+
? _.get(item, this.component.valueProperty)
|
|
293
|
+
: item;
|
|
294
|
+
if (this.component.type === 'radio' && typeof value !== 'string') {
|
|
295
|
+
const uuid = uuidv4();
|
|
296
|
+
this.valuesMap.set(uuid, value);
|
|
297
|
+
return uuid;
|
|
298
|
+
}
|
|
299
|
+
return value;
|
|
300
|
+
}
|
|
301
|
+
getValueByInput(input) {
|
|
302
|
+
const inputValue = input.value;
|
|
303
|
+
return this.valuesMap.has(inputValue)
|
|
304
|
+
? this.valuesMap.get(inputValue)
|
|
305
|
+
: inputValue;
|
|
306
|
+
}
|
|
280
307
|
loadItems(url, search, headers, options, method, body) {
|
|
281
308
|
if (this.optionsLoaded) {
|
|
282
309
|
this.itemsLoadedResolve();
|
|
@@ -327,7 +354,7 @@ export default class RadioComponent extends ListComponent {
|
|
|
327
354
|
label: this.itemTemplate(item)
|
|
328
355
|
};
|
|
329
356
|
if (_.isEqual(item, this.selectData || _.pick(this.dataValue, _.keys(item)))) {
|
|
330
|
-
this.loadedOptions[i].value = this.dataValue;
|
|
357
|
+
this.loadedOptions[i].value = this.prepareValue(this.dataValue, { skipValueProperty: true });
|
|
331
358
|
}
|
|
332
359
|
});
|
|
333
360
|
this.optionsLoaded = true;
|
|
@@ -337,12 +364,15 @@ export default class RadioComponent extends ListComponent {
|
|
|
337
364
|
const listData = [];
|
|
338
365
|
items?.forEach((item, i) => {
|
|
339
366
|
const valueAtProperty = _.get(item, this.component.valueProperty);
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
367
|
+
const value = this.prepareValue(item);
|
|
368
|
+
const label = this.component.valueProperty
|
|
369
|
+
? this.itemTemplate(item, valueAtProperty, i)
|
|
370
|
+
: this.itemTemplate(item, item, i);
|
|
371
|
+
this.loadedOptions[i] = { label, value };
|
|
372
|
+
listData.push(this.templateData[i]);
|
|
373
|
+
if (this.valuesMap.has(value)) {
|
|
374
|
+
this.templateData[value] = this.templateData[i];
|
|
375
|
+
}
|
|
346
376
|
if (!this.isRadio && (_.isObject(value) || _.isBoolean(value) || _.isUndefined(value))) {
|
|
347
377
|
this.loadedOptions[i].invalid = true;
|
|
348
378
|
}
|
|
@@ -365,7 +395,9 @@ export default class RadioComponent extends ListComponent {
|
|
|
365
395
|
const value = this.dataValue;
|
|
366
396
|
this.refs.wrapper.forEach((wrapper, index) => {
|
|
367
397
|
const input = this.refs.input[index];
|
|
368
|
-
const checked = (input.type === 'checkbox')
|
|
398
|
+
const checked = (input.type === 'checkbox')
|
|
399
|
+
? value[input.value] || input.checked
|
|
400
|
+
: _.isEqual(this.normalizeValue(this.getValueByInput(input)), value);
|
|
369
401
|
if (checked) {
|
|
370
402
|
//add class to container when selected
|
|
371
403
|
this.addClass(wrapper, this.optionSelectedClass);
|
|
@@ -379,10 +411,25 @@ export default class RadioComponent extends ListComponent {
|
|
|
379
411
|
});
|
|
380
412
|
}
|
|
381
413
|
}
|
|
414
|
+
setMetadata(value) {
|
|
415
|
+
let key = value;
|
|
416
|
+
if (typeof value !== 'string') {
|
|
417
|
+
const checkedInput = Array.prototype.find.call(this.refs.input, (input => input.type === 'radio' && input.getAttribute('checked')));
|
|
418
|
+
key = checkedInput?.value || key;
|
|
419
|
+
}
|
|
420
|
+
if (this.isSelectURL && this.templateData && this.templateData[key]) {
|
|
421
|
+
const submission = this.root.submission;
|
|
422
|
+
if (!submission.metadata.selectData) {
|
|
423
|
+
submission.metadata.selectData = {};
|
|
424
|
+
}
|
|
425
|
+
_.set(submission.metadata.selectData, this.path, this.templateData[key]);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
382
428
|
updateValue(value, flags) {
|
|
383
429
|
const changed = super.updateValue(value, flags);
|
|
384
430
|
if (changed) {
|
|
385
431
|
this.setSelectedClasses();
|
|
432
|
+
this.setMetadata(this.dataValue);
|
|
386
433
|
}
|
|
387
434
|
if (!flags || !flags.modified || !this.isRadio) {
|
|
388
435
|
if (changed) {
|
|
@@ -438,13 +485,9 @@ export default class RadioComponent extends ListComponent {
|
|
|
438
485
|
value = !(!value || value.toString() === 'false');
|
|
439
486
|
break;
|
|
440
487
|
}
|
|
441
|
-
if (this.isSelectURL && this.templateData && this.templateData[value]) {
|
|
442
|
-
const submission = this.root.submission;
|
|
443
|
-
if (!submission.metadata.selectData) {
|
|
444
|
-
submission.metadata.selectData = {};
|
|
445
|
-
}
|
|
446
|
-
_.set(submission.metadata.selectData, this.path, this.templateData[value]);
|
|
447
|
-
}
|
|
448
488
|
return super.normalizeValue(value);
|
|
449
489
|
}
|
|
490
|
+
isSingleInputValue() {
|
|
491
|
+
return true;
|
|
492
|
+
}
|
|
450
493
|
}
|
|
@@ -141,6 +141,14 @@ export default class SelectBoxesComponent extends RadioComponent {
|
|
|
141
141
|
checkedValues.forEach((value) => selectData.push(this.templateData[value]));
|
|
142
142
|
_.set(submission.metadata.selectData, this.path, selectData);
|
|
143
143
|
}
|
|
144
|
+
// Ensure that for dataSrc == 'values' that there are not any other superfluous values.
|
|
145
|
+
if (this.component.dataSrc === 'values') {
|
|
146
|
+
for (const key in value) {
|
|
147
|
+
if (!this.component.values.find((val) => val.value === key)) {
|
|
148
|
+
delete value[key];
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
144
152
|
return value;
|
|
145
153
|
}
|
|
146
154
|
/**
|