({ref, cid, helpid, onChange, options, readonly = false, value, controlProps = {}, optionsLoaded, optionsReloadBasis, disabled, onError, ...props})
| 924 | }; |
| 925 | |
| 926 | export function InputSelect({ref, cid, helpid, onChange, options, readonly = false, value, controlProps = {}, optionsLoaded, optionsReloadBasis, disabled, onError, ...props}) { |
| 927 | const [[finalOptions, isLoading], setFinalOptions] = useState([[], true]); |
| 928 | // Force options to reload on component remount (each mount gets a new ID) |
| 929 | const [mountId] = useState(() => Math.random()); |
| 930 | const theme = useTheme(); |
| 931 | |
| 932 | useWindowSize(); |
| 933 | |
| 934 | /* React will always take options let as changed parameter. So, |
| 935 | We cannot run the below effect with options dependency as it will keep on |
| 936 | loading the options. optionsReloadBasis is helpful to avoid repeated |
| 937 | options load. If optionsReloadBasis value changes, then options will be loaded again. |
| 938 | */ |
| 939 | useEffect(() => { |
| 940 | let optPromise = options, umounted = false; |
| 941 | if (typeof options === 'function') { |
| 942 | optPromise = options(); |
| 943 | } |
| 944 | setFinalOptions([[], true]); |
| 945 | Promise.resolve(optPromise) |
| 946 | .then((res) => { |
| 947 | /* If component unmounted, dont update state */ |
| 948 | if (!umounted) { |
| 949 | optionsLoaded?.(res, value); |
| 950 | /* Auto select if any option has key as selected */ |
| 951 | const flatRes = flattenSelectOptions(res || []); |
| 952 | let selectedVal; |
| 953 | if (controlProps.multiple) { |
| 954 | selectedVal = _.filter(flatRes, (o) => o.selected)?.map((o) => o.value); |
| 955 | } else { |
| 956 | selectedVal = _.find(flatRes, (o) => o.selected)?.value; |
| 957 | } |
| 958 | |
| 959 | if ((!_.isUndefined(selectedVal) && !_.isArray(selectedVal)) || (_.isArray(selectedVal) && selectedVal.length != 0)) { |
| 960 | onChange?.(selectedVal); |
| 961 | } |
| 962 | setFinalOptions([res || [], false]); |
| 963 | } |
| 964 | }) |
| 965 | .catch((err)=>{ |
| 966 | let error_msg = err?.response?.data?.errormsg || err?.message || 'Unknown error'; |
| 967 | onError?.(error_msg); |
| 968 | setFinalOptions([[], false]); |
| 969 | }); |
| 970 | return () => umounted = true; |
| 971 | }, [optionsReloadBasis, mountId]); |
| 972 | |
| 973 | /* Apply filter if any */ |
| 974 | const filteredOptions = (controlProps.filter?.(finalOptions)) || finalOptions; |
| 975 | const flatFiltered = flattenSelectOptions(filteredOptions); |
| 976 | let realValue = getRealValue(flatFiltered, value, controlProps.creatable, controlProps.formatter); |
| 977 | if (realValue && _.isPlainObject(realValue) && _.isUndefined(realValue.value)) { |
| 978 | console.error('Undefined option value not allowed', realValue, filteredOptions); |
| 979 | } |
| 980 | const otherProps = { |
| 981 | isSearchable: !readonly, |
| 982 | isClearable: !readonly && (!_.isUndefined(controlProps.allowClear) ? controlProps.allowClear : true), |
| 983 | isDisabled: Boolean(disabled), |
nothing calls this directly
no test coverage detected