JedWatson / react-select

The Select Component for React.js
https://react-select.com/
MIT License
27.42k stars 4.1k forks source link

AsyncCreatableSelect not allowing to enter more than character to search or create #5922

Open Kranthi32 opened 2 weeks ago

Kranthi32 commented 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 []; } };

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]);

if (isLoading) return

Loading...

; if (error) return
Error: {error.message}
;

return ( <div className={relative}> {/ Label /} {Label && ( <label className={${LabelClass}} style={{ color: LabelColor }}> {Label} )}

  {/* 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;