[Feature] Option for 'Select' component to auto-select the one-and-only option
This issue is about adding a new option to a select component with "dataSrc": "resource".
Suppose the dynamic select filtering example was working as expected. Wouldn't it be useful to be able to specify that the Model should auto-select if there was only a single Model available for a selected Make? (And then, maybe the select input could also be disabled, since no other option exists anyway?)
Should this be added to formio.js? Is it possible to implement this already using existing mechanisms without modifying the library? I tried to put some code like
const options = instance.selectOptions;
if (_.isEmpty(input) && options.length === 1) {
const newVal = options[0].value;
instance.setValue(newVal);
_.set(data, component.key, newVal);
}
in various "custom JS" places, but I haven't found a way to trigger it reliably right at the time when selectOptions are updated, e.g. as a result of a changed filter query. Is there an existing event that can be used as a trigger, like 'selectOptionsChanged'?
I don't believe we have an event for that - you may be able to add one in setItems:
https://github.com/formio/formio.js/blob/1ee427a7e98ffab803e900255c3ab5c0ea89a72d/src/components/select/Select.js#L222L332
Ok, so one possible solution might look like this:
diff --git a/src/components/select/Select.js b/src/components/select/Select.js
index 4cee86a2b..b60befac9 100644
--- a/src/components/select/Select.js
+++ b/src/components/select/Select.js
@@ -329,6 +329,15 @@ export default class SelectComponent extends Field {
// Say we are done loading the items.
this.itemsLoadedResolve();
+
+ // Emit an event suitable for triggering custom logic
+ const eventName = this.component.optionsChangedEvent;
+ if (eventName) {
+ this.emit(eventName, {
+ component: this.component,
+ items: items
+ });
+ }
}
/* eslint-enable max-statements */
diff --git a/src/components/select/editForm/Select.edit.data.js b/src/components/select/editForm/Select.edit.data.js
index 09a41e605..e38949456 100644
--- a/src/components/select/editForm/Select.edit.data.js
+++ b/src/components/select/editForm/Select.edit.data.js
@@ -496,6 +496,14 @@ export default [
},
},
},
+ {
+ type: 'textfield',
+ label: 'Options Changed Event',
+ key: 'optionsChangedEvent',
+ input: true,
+ weight: 20.5,
+ tooltip: 'The event to fire when the select options may have changed.'
+ },
{
type: 'checkbox',
input: true,
Such an event can then be used to trigger a custom logic action:
"label": "Select Foo",
"limit": 100,
- "logic": [],
+ "logic": [
+ {
+ "name": "fooAutoSelect",
+ "actions": [
+ {
+ "name": "fooAutoSelect",
+ "type": "value",
+ "value": "//
+MyUtils.autoSelect(data, instance, component);"
+ }
+ ],
+ "trigger": {
+ "type": "event",
+ "event": "fooOptionsChanged"
+ }
+ }
+ ],
"width": 12,
"filter": "{{MyUtils.fooFilter(data)}}",
...
+ "optionsChangedEvent": "fooOptionsChanged",
... with e.g. the following implementation, which also displays the Select component as disabled in case of an auto-selected option:
export function autoSelect(data, instance, component) {
const currVal = _.get(data, component.key);
const options = instance.selectOptions;
if (options.length === 1) {
const newVal = options[0].value;
if (currVal !== newVal) {
//if (newVal && newVal.data) {
// console.debug(`Auto-selecting ${component.key}: ${currVal && currVal.data} ==> {data: ${JSON.stringify(newVal.data)}, ...}`);
//}
instance.setValue(newVal);
_.set(data, component.key, newVal);
instance.options.readOnly = true;
instance.redraw();
}
}
else {
if (instance.options.readOnly) {
//console.debug(`Auto-select: ${component.key} will be enabled.`);
instance.options.readOnly = undefined;
instance.redraw();
}
}
}
Comments?
By the way, as far as I can see there is no way to access the event data (e.g. items in this case) from a (custom logic) JS 'action' triggered by a certain event name. Is this correct?
You are correct that there is no event that automatically fires when the options are refreshed. You can see the function callback at https://github.com/formio/formio.js/blob/1ee427a7e98ffab803e900255c3ab5c0ea89a72d/src/components/select/Select.js#L461-L473 that is fired when the options are refreshed.
One thing that might work is that instead of setting the value to emptyValue at https://github.com/formio/formio.js/blob/1ee427a7e98ffab803e900255c3ab5c0ea89a72d/src/components/select/Select.js#L463 we could set it to the defaultValue so that it runs the customDefaultValue logic again. You could grab the items[0] there as the default value.
We're currently addressing a backlog of GitHub issues, and as part of this effort, some inactive issues may be marked as closed. This isn't a dismissal, but a step toward more efficient tracking. Closing this thread as it is outdated. Please re-open if it is still relevant. Thank you for your contribution!
I was just looking at a feature like described above, can we reopen this please.
I have logged a ticket for review by our planning team. In the meantime, we are always willing to review any contributions related to this behavior. Internal reference: FIO-8623
After review, we don't expect to resource a developer to investigate this in the near future but would be happy to review any contributions to resolve this behavior.