Open Kranthi32 opened 2 weeks ago
this is my code below mentioned.AsyncCreatableSelect not allowing to enter more than character to search or create please suggest
import React, { useState, useEffect, useCallback } from 'react'; import Select, { StylesConfig, ActionMeta, components } from 'react-select'; import AsyncSelect from 'react-select/async'; import makeAnimated from 'react-select/animated'; import CreatableSelect from 'react-select/creatable'; import AsyncCreatableSelect from 'react-select/async-creatable'; import ReactTooltip, { Tooltip } from "react-tooltip"; import { DropdownProps, Option } from '@/Interface/Dropdown'; import dropdownData from '@/Mockup/Dropdown.json'; import useFetch from '@/Hooks/useFetch'; import { encrypt, decrypt } from '@/Utils/CryptoUtils';
const { alignmentClassMap }: { alignmentClassMap: Record<string, string> } = dropdownData;
const getSelectContainer = (options: { tooltipText: string; tooltipId: string }) => (props: any) => ( <components.SelectContainer {...props} innerProps={{ ...props.innerProps, 'data-tip': options.tooltipText, 'data-for': options.tooltipId, }} /> );
const Dropdown: React.FC = ({ Label, Name, Class, Color = '#000000', Placeholder, Disabled, ReadOnly = false, Width = 'w-full', Alignment = 'left', Required = false, Options, Value: initialValue = null, Reset = false, IsSearchable = false, Rtl = false, LabelClass, LabelColor = "#000000", Icon, IsMultiSelect = false, EnableTooltip = true, TooltipText = "dsagfsdg", ValidationMessage, onChange, OptionsUrl = null, Async = false, AsyncOptionsUrl = null, Algorithm = 'AES', Encryption = true, Decryption = true, BlockHelper, CreateNew = false,
}) => {
const [selectedValue, setSelectedValue] = useState<Option | Option[] | null>(initialValue); const [optionsToUse, setOptionsToUse] = useState<Option[]>(Options); const { data, isLoading, error } = useFetch<Option[]>(OptionsUrl || ''); const [inputValue, setInputValue] = useState(''); const [inputValueState, setInputValueState] = useState('');
useEffect(() => { if (OptionsUrl) { if (data) { setOptionsToUse(data); } } else { setOptionsToUse(Options); } }, [Options, OptionsUrl, data]);
// load options using API call const loadOptionsPromise = async (inputValue: string): Promise<Option[]> => { try { const response = await fetch(${AsyncOptionsUrl}?search=${inputValue}); const json = await response.json(); return json; } catch (error) { console.error('Error loading options:', error); return []; } };
${AsyncOptionsUrl}?search=${inputValue}
const handleOnInputChange = (inputValue: string) => { let result = inputValue.substring(0,3); const forbiddenCharacters = /[^a-zA-Z0-9.-_ ]/g; if(result.match(forbiddenCharacters)){ result = result.replace(forbiddenCharacters, ''); } setInputValueState(result); }
const createOption = (label: string) => ({ label, value: label.toLowerCase().replace(/\W/g, ''), });
const handleCreate = (inputValue: string) => { const newOption = createOption(inputValue); setOptionsToUse((prev) => { const updatedOptions = [...prev, newOption]; console.log('Updated optionsToUse:', updatedOptions); return updatedOptions; }); console.info('optionstoUse',optionsToUse) if (IsMultiSelect && Array.isArray(selectedValue)) { const newSelectedValues = [...selectedValue, newOption]; setSelectedValue(newSelectedValues); } else { setSelectedValue(newOption); }
setInputValue('');
};
const customStyles: StylesConfig<Option, boolean> = { control: (provided, state) => ({ ...provided, width: '100%', color: Color, direction: Rtl ? 'rtl' : 'ltr', borderColor: state.isFocused ? (Required && (!selectedValue || (Array.isArray(selectedValue) && selectedValue.length === 0))) ? 'red' : provided.borderColor : provided.borderColor, '&:hover': { borderColor: state.isFocused ? (Required && (!selectedValue || (Array.isArray(selectedValue) && selectedValue.length === 0))) ? 'red' : provided.borderColor : provided.borderColor, }, }), placeholder: (provided) => ({ ...provided, color: Color, }), singleValue: (provided) => ({ ...provided, color: Color, }), multiValue: (provided) => ({ ...provided, }), multiValueLabel: (provided) => ({ ...provided, color: Color, }), multiValueRemove: (provided) => ({ ...provided, color: Color, }), input: (provided) => ({ ...provided, color: Color, }), };
const animatedComponents = makeAnimated();
// Handle change in selected value(s) const handleChange = (option: any) => { setSelectedValue(option);
if (onChange) { onChange(Name, option); }
const handleInputChange = (newValue: string) => { setInputValue(newValue); return newValue; };
useEffect(() => { if (Encryption && selectedValue) { const encryptedValue = Array.isArray(selectedValue) ? selectedValue.map(val => encrypt(val.value, Algorithm)).join(',') : encrypt(selectedValue.value, Algorithm); const selectElement = document.querySelector([name="${Name}"]); if (selectElement) { selectElement.setAttribute('data-encrypted-value', encryptedValue); } } }, [selectedValue, Encryption, Algorithm, Name]);
[name="${Name}"]
if (isLoading) return
Loading...
return ( <div className={relative}> {/ Label /} {Label && ( <label className={${LabelClass}} style={{ color: LabelColor }}> {Label} )}
relative
${LabelClass}
{/* Dropdown */} <div className={`relative flex items-center ${!Rtl ? alignmentClassMap[Alignment] : ''}`}> {Async ? CreateNew ? // Async - true, create New Option - true <AsyncCreatableSelect name={Name} classNamePrefix="react-select" placeholder={Placeholder} isDisabled={Disabled || ReadOnly} isMulti={IsMultiSelect} isClearable={Reset} loadOptions={loadOptionsPromise} defaultOptions={optionsToUse} options={optionsToUse} defaultValue={initialValue} value={selectedValue} onChange={(option: any) => handleChange(option)} allowCreateWhileLoading={true} isSearchable={IsSearchable} onInputChange={handleInputChange} inputValue={inputValue} noOptionsMessage={() => (isLoading ? 'Loading...' : 'No options')} styles={customStyles} components={{ SelectContainer: getSelectContainer({ tooltipText: TooltipText, tooltipId: 'currency-tooltip', }), }} data-tooltip-id={EnableTooltip ? "currency-tooltip" : undefined} data-tooltip-content={EnableTooltip ? TooltipText : ValidationMessage} className={`${Class} ${Width} border ${Required && (!selectedValue || (Array.isArray(selectedValue) && selectedValue.length === 0)) ? 'border-red-500' : 'border-gray-300'}`} onCreateOption={handleCreate} /> : <AsyncSelect // Async - true, create New Option - false name={Name} classNamePrefix="react-select" placeholder={Placeholder} isDisabled={Disabled || ReadOnly} isMulti={IsMultiSelect} isClearable={Reset} loadOptions={loadOptionsPromise} defaultOptions={optionsToUse} options={optionsToUse} defaultValue={initialValue} value={selectedValue} onChange={(option) => handleChange(option)} isSearchable={IsSearchable} onInputChange={handleInputChange} inputValue={inputValue} noOptionsMessage={() => (isLoading ? 'Loading...' : 'No options')} styles={customStyles} components={{ SelectContainer: getSelectContainer({ tooltipText: TooltipText, tooltipId: 'currency-tooltip', }), }} data-tooltip-id={EnableTooltip ? "currency-tooltip" : undefined} data-tooltip-content={EnableTooltip ? TooltipText : ValidationMessage} className={`${Class} ${Width} border ${Required && (!selectedValue || (Array.isArray(selectedValue) && selectedValue.length === 0)) ? 'border-red-500' : 'border-gray-300'}`} /> : //Normal Select Async False CreateNew ? //Async false create New <CreatableSelect name={Name} classNamePrefix="react-select" placeholder={Placeholder} isDisabled={Disabled || ReadOnly} isMulti={IsMultiSelect} isClearable={Reset} options={optionsToUse} defaultValue={initialValue} value={selectedValue} onChange={(option) => handleChange(option)} isSearchable={IsSearchable} styles={customStyles} components={{ SelectContainer: getSelectContainer({ tooltipText: TooltipText, tooltipId: 'currency-tooltip', }), }} data-tooltip-id={EnableTooltip ? "currency-tooltip" : undefined} data-tooltip-content={EnableTooltip ? TooltipText : ValidationMessage} className={`${Class} ${Width} border ${Required && (!selectedValue || (Array.isArray(selectedValue) && selectedValue.length === 0)) ? 'border-red-500' : 'border-gray-300'}`} onCreateOption={handleCreate} /> : //Async false create New false <Select name={Name} classNamePrefix="react-select" placeholder={Placeholder} isDisabled={Disabled || ReadOnly} isMulti={IsMultiSelect} isClearable={Reset} options={optionsToUse} defaultValue={initialValue} value={selectedValue} onChange={(option) => handleChange(option)} isSearchable={IsSearchable} styles={customStyles} components={{ SelectContainer: getSelectContainer({ tooltipText: TooltipText, tooltipId: 'currency-tooltip', }), }} data-tooltip-id={EnableTooltip ? "currency-tooltip" : undefined} data-tooltip-content={EnableTooltip ? TooltipText : ValidationMessage} className={`${Class} ${Width} border ${Required && (!selectedValue || (Array.isArray(selectedValue) && selectedValue.length === 0)) ? 'border-red-500' : 'border-gray-300'}`} /> } </div> {/* Tooltip */} {EnableTooltip && ( <Tooltip variant="info" place="bottom" id='currency-tooltip' /> )} {/* Block Helper */} {BlockHelper && ( <p className="mt-2 text-sm text-gray-500"> {(BlockHelper || '')} </p> )} {/* Validation Message */} {Required && (!selectedValue || (Array.isArray(selectedValue) && selectedValue.length === 0)) && ValidationMessage && ( <span className="validation-message"> {ValidationMessage} </span> )} </div>
); };
export default Dropdown;
this is my code below mentioned.AsyncCreatableSelect not allowing to enter more than character to search or create please suggest
import React, { useState, useEffect, useCallback } from 'react'; import Select, { StylesConfig, ActionMeta, components } from 'react-select'; import AsyncSelect from 'react-select/async'; import makeAnimated from 'react-select/animated'; import CreatableSelect from 'react-select/creatable'; import AsyncCreatableSelect from 'react-select/async-creatable'; import ReactTooltip, { Tooltip } from "react-tooltip"; import { DropdownProps, Option } from '@/Interface/Dropdown'; import dropdownData from '@/Mockup/Dropdown.json'; import useFetch from '@/Hooks/useFetch'; import { encrypt, decrypt } from '@/Utils/CryptoUtils';
const { alignmentClassMap }: { alignmentClassMap: Record<string, string> } = dropdownData;
const getSelectContainer = (options: { tooltipText: string; tooltipId: string }) => (props: any) => ( <components.SelectContainer {...props} innerProps={{ ...props.innerProps, 'data-tip': options.tooltipText, 'data-for': options.tooltipId, }} /> );
const Dropdown: React.FC = ({
Label,
Name,
Class,
Color = '#000000',
Placeholder,
Disabled,
ReadOnly = false,
Width = 'w-full',
Alignment = 'left',
Required = false,
Options,
Value: initialValue = null,
Reset = false,
IsSearchable = false,
Rtl = false,
LabelClass,
LabelColor = "#000000",
Icon,
IsMultiSelect = false,
EnableTooltip = true,
TooltipText = "dsagfsdg",
ValidationMessage,
onChange,
OptionsUrl = null,
Async = false,
AsyncOptionsUrl = null,
Algorithm = 'AES',
Encryption = true,
Decryption = true,
BlockHelper,
CreateNew = false,
}) => {
const [selectedValue, setSelectedValue] = useState<Option | Option[] | null>(initialValue); const [optionsToUse, setOptionsToUse] = useState<Option[]>(Options); const { data, isLoading, error } = useFetch<Option[]>(OptionsUrl || ''); const [inputValue, setInputValue] = useState('');
const [inputValueState, setInputValueState] = useState('');
useEffect(() => { if (OptionsUrl) { if (data) { setOptionsToUse(data); } } else { setOptionsToUse(Options); } }, [Options, OptionsUrl, data]);
// load options using API call const loadOptionsPromise = async (inputValue: string): Promise<Option[]> => { try { const response = await fetch(
${AsyncOptionsUrl}?search=${inputValue}
); const json = await response.json(); return json; } catch (error) { console.error('Error loading options:', error); return []; } };const handleOnInputChange = (inputValue: string) => { let result = inputValue.substring(0,3); const forbiddenCharacters = /[^a-zA-Z0-9.-_ ]/g; if(result.match(forbiddenCharacters)){ result = result.replace(forbiddenCharacters, ''); } setInputValueState(result); }
const createOption = (label: string) => ({ label, value: label.toLowerCase().replace(/\W/g, ''), });
const handleCreate = (inputValue: string) => { const newOption = createOption(inputValue); setOptionsToUse((prev) => { const updatedOptions = [...prev, newOption]; console.log('Updated optionsToUse:', updatedOptions);
return updatedOptions; }); console.info('optionstoUse',optionsToUse) if (IsMultiSelect && Array.isArray(selectedValue)) { const newSelectedValues = [...selectedValue, newOption]; setSelectedValue(newSelectedValues); } else { setSelectedValue(newOption); }
};
const customStyles: StylesConfig<Option, boolean> = { control: (provided, state) => ({ ...provided, width: '100%', color: Color, direction: Rtl ? 'rtl' : 'ltr', borderColor: state.isFocused ? (Required && (!selectedValue || (Array.isArray(selectedValue) && selectedValue.length === 0))) ? 'red' : provided.borderColor : provided.borderColor, '&:hover': { borderColor: state.isFocused ? (Required && (!selectedValue || (Array.isArray(selectedValue) && selectedValue.length === 0))) ? 'red' : provided.borderColor : provided.borderColor, }, }), placeholder: (provided) => ({ ...provided, color: Color, }), singleValue: (provided) => ({ ...provided, color: Color, }), multiValue: (provided) => ({ ...provided, }), multiValueLabel: (provided) => ({ ...provided, color: Color, }), multiValueRemove: (provided) => ({ ...provided, color: Color, }), input: (provided) => ({ ...provided, color: Color, }), };
const animatedComponents = makeAnimated();
// Handle change in selected value(s) const handleChange = (option: any) => { setSelectedValue(option);
};
const handleInputChange = (newValue: string) => { setInputValue(newValue); return newValue; };
useEffect(() => { if (Encryption && selectedValue) { const encryptedValue = Array.isArray(selectedValue) ? selectedValue.map(val => encrypt(val.value, Algorithm)).join(',') : encrypt(selectedValue.value, Algorithm); const selectElement = document.querySelector(
[name="${Name}"]
); if (selectElement) { selectElement.setAttribute('data-encrypted-value', encryptedValue); } } }, [selectedValue, Encryption, Algorithm, Name]);if (isLoading) return
Loading...
; if (error) returnreturn ( <div className={
relative
}> {/ Label /} {Label && ( <label className={${LabelClass}
} style={{ color: LabelColor }}> {Label} )}); };
export default Dropdown;