i am using creatable select where i want to hide "create new" menu option. here is my
CodeSandbox i tried following but no luck promptTextCreator={() => false}
thanks you and appreciate any help
// try this way
return (
<CreatableSelect
isClearable
onChange={this.handleChange}
onInputChange={this.handleInputChange}
options={colourOptions}
noOptionsMessage={() => null}
// isValidNewOption={() => true}
// or `isValidNewOption={() => false}`
promptTextCreator={() => false}
/>
);
If you want to hide the create new value message at all times while still being able to create new values, you have to use the prop formatCreateLabel as follows formatCreateLabel={() => undefined} when you define your CreatableSelect.
Disabling create label via formatCreateLabel={() => undefined} is the right direction but the menu list sill shows empty space instead of not showing at all which is what you may prefer.
You may want to hide the menu list completely when there is no option by setting the menu list display to none
// Remember to define a unique id for your component in the constructor
// so you can target the right menu list element to hide it
id = "";
constructor(props) {
super(props);
this.id = "react-select_" + Math.random().toFixed(8).slice(2);
}
handleInputChange = (inputValue: any, actionMeta: any) => {
setTimeout(() => {
const menuEl = document.querySelector(`#${this.id} [class*="-menu"]`);
const menuListEl = document.querySelector(
`#${this.id} [class*="MenuList"]`
);
if (
menuListEl.children.length === 1 &&
menuListEl.children[0].innerHTML === ""
) {
menuEl.style.display = "none";
} else {
menuEl.style.display = "block";
}
});
};
...
<CreatableSelect
id={this.id}
onInputChange={this.handleInputChange}
formatCreateLabel={() => undefined}
...
/>
Live Demo
Just add these props:
menuIsOpen={false} and components={{ DropdownIndicator: null }}
Then handle onKeyDown and onInputChange event as explained in => https://react-select.com/creatable, have a look into "Multi-select text input" section
Here is the complete example:
import React, { Component } from 'react';
import CreatableSelect from 'react-select/creatable';
const components = {
DropdownIndicator: null,
};
const createOption = (label: string) => ({
label,
value: label,
});
export default class CreatableInputOnly extends Component<*, State> {
state = {
inputValue: '',
value: [],
};
handleChange = (value: any, actionMeta: any) => {
this.setState({ value });
};
handleInputChange = (inputValue: string) => {
this.setState({ inputValue });
};
handleKeyDown = (event: SyntheticKeyboardEvent<HTMLElement>) => {
const { inputValue, value } = this.state;
if (!inputValue) return;
switch (event.key) {
case 'Enter':
case 'Tab':
this.setState({
inputValue: '',
value: [...value, createOption(inputValue)],
});
event.preventDefault();
}
};
render() {
const { inputValue, value } = this.state;
return (
<CreatableSelect
components={components}
inputValue={inputValue}
isClearable
isMulti
menuIsOpen={false}
onChange={this.handleChange}
onInputChange={this.handleInputChange}
onKeyDown={this.handleKeyDown}
placeholder="Type something and press enter..."
value={value}
/>
);
}
}
Just add
<CreatableSelect
components={{
...components,
Menu: () => null
}}
/>
Just treat all the new options as invalid, it will show "No options" message:
<CreatableSelect isValidNewOption={() => false}/>
You may want to show "Create" option to user but if element exists or any other reason the "Create" option should be hidden.
For exp:
options=[
{label:"A - 1",value:"A"},
{label:"B - 1",value:"B"}
{label:"C - 1",value:"C"}
{label:"D - 1",value:"D"}
]
In my case, user can only Create A, B, C, D but i have formatted their input to make the label look as "A - 1" , "B - 1" and so on. Now if user again enters A, or B or C or D, it will not match with "A - 1", or "B - 1" or "C - 1" or "D - 1" respectively, in this case i want to hide "Create" option because I am already accepting that value but with different format.
So my logic should go as
<CreatableSelect
name="options"
options={options}
placeholder="Select or Create"
isSearchable
onChange={(option) => appendLabel(option.value)}
value={null}
isValidNewOption={(inputValue)=>
(options.filter((lab)=>lab?.label?.split(" — ")
[0].trim().toLowerCase()===inputValue.toLowerCase()).length>0?false:`Create ${inputValue}`}
/>
Related
I am trying to retrieve the checked values of the checkboxes and save them into array.
I tried :
arr.push(setNewItem(checked))
arr.push(e.target.value.checked)
arr.push(items.checked)
But these return type error or undefined values.
const [checkedItems, setCheckedItems] = useState([]);
const handleChange = (e) => {
if (e.target.checked) {
var arr = [...checkedItems];
//arr.push(setNewItem(e.target.value.checked));
setCheckedItems(arr);
console.log(arr);
} else {
checkedItems = "";
}
setIsChecked((current) => !current);
};
return (
<div className="App">
<StyleForm>
<StyleInput
type="text"
placeholder="Add"
value={newItem}
onChange={(e) => setNewItem(e.target.value)}
onKeyPress={handleOnKeyPress}
/>
<ButtonAddStyle onClick={() => addItem()}>add</ButtonAddStyle>
<StyleUl>
{items.map((item) => {
return (
<StyleLi key={item.id}>
<StyleCheckBox
type="checkbox"
value={isChecked}
onChange={handleChange}
/>
{item.value}
{""}
<ButtonDelStyle onClick={() => deleteItem(item.id)}>
X
</ButtonDelStyle>
</StyleLi>
);
})}
</StyleUl>
</StyleForm>
</div>
);
arr.push(e.target.checked);
Is the way to go and get rif of :
else {
checkedItems = "";
}
you cannot update a hook this way you will get an error when you try to unchek an input:
Uncaught TypeError : Assignment to constant variable
Now let's see what you are trying to do you are storing e.target.checked each time an input is cheked so checkedItems will look something like this :
[true, true, true, true, true, true, true, true]
why do you need this ? better is to store the ids of checked items :
const handleChange = (isChecked, id) => {
var arr = [...checkedItems];
if (isChecked) {
arr.push(id);
setCheckedItems(arr);
} else {
setCheckedItems(checkedItems.filter((storedId) => storedId !== id)); // delete the id from checkedItems if the corresponding input is unckecked
}
};
and from jsx :
<StyleCheckBox
type="checkbox"
value={item.id}
onChange={(e) => {
handleChange(e.target.checked, item.id);
}}
/>;
Now look at this :
<StyleCheckBox
value={isChecked} // this line
>
you are mapping through items creating multiple checkBoxes but all of them share the same value. and the value attribute of an input of type checkbox is not what you think it is, learn more here. so you can use value={item.id} to have an unique value for each input and get rid of isChecked useState hook you really don't need it
this could solve your problem.
const [checkedItems, setCheckedItems] = useState([]);
const handleChange = (e) => {
setCheckedItems( prev => [...prev, e.target.checked]);
setIsChecked((current) => !current);
};
I have a dropdown made with react-select, with multiple options that i get from an api. The code is working, when clicked the dropdown show the options, but when I select one option it stop showing the other ones. I don't what could it be since the isMulti prop is on.
Here is the code:
export const DropDown = ({ itemsOption, placeholder }) => {
const [options, setOptions] = useState([]);
const loadOptions = (op) => {
api.get(`${op}`).then(({ data }) => {
setOptions(
data.map((item) => {
return {
key: item.code,
label: item.name_ptbr,
};
})
);
});
};
useEffect(() => {
loadOptions(itemsOption);
}, []);
return (
<>
<DropStyled>
<Select
isMulti
options={options}
name={placeholder}
placeholder={placeholder}
closeMenuOnSelect={false}
/>
</DropStyled>
</>
);
};
An option needs a value property for react-select to map the data to its options.
So when mapping over the fetched data, add value along with label and key.
return {
key: item.code,
label: item.name_ptbr,
value: item.name_ptbr,
};
I am working on an app that allows for doctors to fill out intake forms during surgeries or other procedures. On another page of the app, the doctor's are able to select favorite codes from the whole code list. A component of the intake form is an input field that searches a dataset for the doctor's favorite CPT and ICD-10 Codes. The issue is that the doctors do not want to go into the favorite code component to set a favorite while they are filling out the intake form. I created another input component that searches the favorite code list + the global code list. My goal is to create a ternary that shows the favorite code component, but when enter is pressed (assuming the code they are looking for is not in the favorites list) it will hide and the component that shows the favorites + the global list will be visible.
I am new to React so apologizes for the long winded question. Please let me know if you need to see any other code.
{show === true ?
<SearchableDropdown
label="ICD-10 Code"
showAddButton={false}
showCaretIcon={true}
options={fdata?.icdCodes?.map((code) => ({
content: `${code.code}` + ' - ' + `${code.description}`,
key: code.id,
value: code.id,
}))}
displayValue={state.icdCodes}
value={searchIcd}
onChange={(newValue) => {
setState({
...state,
icdCodes: newValue
});
}}
onKeyUp = {() => setShow(false)}
onSelectOption={(option) => {
setState({
...state,
icdCodes: option?.content,
});
}}
/>
:
<Search
label='ICD-10 Code'
placeholderText={valid ? (
"Search for an ICD-10 code"
) : (
searchText
)}
searchText={searchIcd}
setSearchText={setSearchIcd}
searchFunction={icdAction}
/>
Favorite List
Global List
EDIT: I get an error that states, "(e: any, show: any) => void' is not assignable to type '(newDisplayValue: string) => any'"
const handleKeyDown = (event) => {
if (event.key === 'Enter') {
event.preventDefault();
event.stopPropagation();
setShowFavorites(false);
console.log('keydown')
}
}
{showFavorites === true ?
<SearchableDropdown
label="ICD-10 Code"
showAddButton={false}
showCaretIcon={true}
options={fdata?.icdCodes?.map((code) => ({
content: `${code.code} - ${code.description}`,
key: code.id,
value: code.id,
}))}
displayValue={state.icdCodes}
value={searchIcd}
onChange={(newValue) => {
setState({
...state,
icdCodes: newValue
});
}}
onKeyDown={handleKeyDown}
onSelectOption={(option) => {
setState({
...state,
icdCodes: option?.content,
});
}}
/>
:
<Search
label='ICD-10 Code'
placeholderText={valid ? (
"Search for an ICD-10 code"
) : (
searchText
)}
searchText={searchIcd}
setSearchText={setSearchIcd}
searchFunction={icdAction}
/>
}
Your show variable should be a state for conditional rendering (consider more descriptive name):
const [showFavorites, setShowFavorites] = useState(true);
then your keyboard handler should look like this:
const handleKeyDown = (event) => {
if (event.key === 'Enter') {
event.preventDefault();
event.stopPropagation();
setShowFavorites(false);
}
}
and respectively in <SearchableDropdown>:
onKeyDown={handleKeyDown}
To modify your state when the user press enter in your input, you can do:
const handleKeyUp = (e) => {
if(e.key !== "Enter") return;
//do your logic here
};
//...
<input ... onKeyUp={handleKeyUp} />
I am using react-select and just notice that when I already have value in the input field (either by user type or by choosing the option in menu list), then I blur the input then focus at it again - trying to edit my last input - its just start over from the beginning, not continue from the last character of the input. I just found this issue in the author's github. Its been raised from 2 years ago and still an open issue. Is there really no workaround to achieve this?
I recommend you to use controlled props inputValue and value pair with onChange and onInputChange like the following code:
class App extends Component {
constructor(props) {
super(props);
this.state = {
inputValue: "",
value: ""
};
}
onInputChange = (option, { action }) => {
console.log(option, action);
if (action === "input-change") {
const optionLength = option.length;
const inputValue = this.state.inputValue;
const inputValueLength = inputValue.length;
const newInputValue =
optionLength < inputValueLength
? option
: this.state.inputValue + option[option.length - 1];
this.setState({
inputValue: newInputValue
});
}
};
onChange = option => {
this.setState({
value: option
});
};
render() {
return (
<div className="App">
<Select
options={options}
onChange={this.onChange}
onInputChange={this.onInputChange}
inputValue={this.state.inputValue}
value={this.state.value}
/>
</div>
);
}
}
In react-select v1 the props onSelectResetsInput set to false was doing this job but I guess for v2 you will need to do the trick.
Here a live example.
I'm trying to keep the multiple selection dropdown available from Semanti-UI-React open when I remove a selected item, but still have it close onBlur. I can set closeOnBlur to false and I get the behavior I want for removing the selected item, but then I have to click the arrow on the dropdown to close it. I tried plugging into the relevant events to see if there was a way I could achieve the desired behavior manually, but oddly enough if closeOnBlur is set to false, I don't even get the onBlur event.
Here is my code:
<Dropdown
style={{whiteSpace: 'nowrap', zIndex: 9999}}
upward={true}
search={true}
multiple={true}
selection={true}
loading={loading}
options={options}
value={this.props.selectedCodes || []}
closeOnBlur={false}
onBlur={() => console.log('onBlur')}
onChange={ (e, d) => {
console.log('onChange');
const value = d.value as string[];
const displayValues = value.map(code => {
const lookupEntry = options.find(i => i.value === code);
return lookupEntry ? lookupEntry.text : '';
});
const displayValue = displayValues.reduce(
(result, text) => {
return `${result}, ${text}`;
}, ''\
);
this.props.onSelectionChange(value, displayValue);
}}
onClose={() => console.log('onClose')}
/>
Any suggestions on how to achieve my desired behavior, or insight as to why the onBlur even doesn't fire if closeOnBlur is set to false?
This component supports manual control over it's open/closed status view an open prop. So simply manage that prop via the state of your custom containing class;
getInitialState() {
return { open: false };
},
handleClose() {
this.setState({open: false});
},
handleOpen() {
this.setState({open: true});
}
render() {
return <Dropdown
open={this.state.open}
onBlur={this.handleClose}
onFocus={this.handleOpen}
...
/>;