How to define a max limit of options in react-select? - reactjs

I created a react select component for my app react and I have more than 70 options, for that I want to define a max limit of options that the user can choose to handle it well. Can you please help me?
The code:
export default function ReactSelect(props) {
const animatedComponents = makeAnimated();
return (
<Select
isMulti="true" // allow to select mutli options
isRtl="true" // right to left
name="name" // html name
options={accountsNames} // options
className="basic-multi-select"
classNamePrefix="select"
isSearchable="true" // searchable for the closest one
placeholder="اختر اسم الحساب..." // if there is no option selected
components={animatedComponents}
/>
);
}

You can control the selected options state and disable the options conditionally based on selectedOptions.length like this:
const [selectedOptions, setSelectedOptions] = React.useState([]);
return (
<Select
isMulti
value={selectedOptions}
onChange={(o) => setSelectedOptions(o)}
options={colourOptions}
// only allow user to choose up to 3 options
isOptionDisabled={() => selectedOptions.length >= 3}
className="basic-multi-select"
classNamePrefix="select"
/>
);
Live Demo

This might help:
const MultiSelect = ({valueList, onChange, options, maxLimit = 5}) => {
return (
<Select
value={valueList}
isMulti
onChange={onChange}
options={options}
isOptionDisabled={(option) => valueList.length >= maxLimit}
/>
);
};

Related

select dropdown option set to default when click reset button on react js

I am working on a dropdown select filter and there is a reset button, so I want to reset data whenever I click on it.
this is my select dropdown where I am filtering data
<select
className={style.input}
name="categoryId"
onChange={e => handleCategory(e.target.value)}
>
<option value="" disabled selected>
Select A Categtory
</option>
{props.category_list && props.category_list.length > 0
? props.category_list.map((item, index) => (
<option value={item.categoryId}>{item.categoryName}</option>
))
: null}
</select>
this is onChange method of select
const handleCategory = (value) => {
setErrorMsg(null);
setCategoryID(value);
props.getSubCategoryList(value);
};
and this is a reset button, I tried to make
const handleReset = (value) => {
setReset(true);
setCategoryID('');
setSkillID('');
setLocationId('');
props.getSubCategoryList(1);
};
but the problem is when I click on reset it resets, but the value doesn't change to default one in options also if I change it in {item.categoryName} then three same values appear under options. hope this information is enough.
You need to bind the selected value to select element.
Provide categoryID as a prop to your component.
Set it as the value property of select.
<select
...
...
value={props.categoryID}
onChange={e => handleCategory(e.target.value)}
></select>

Set checkbox checked state of checkbox group programmatically in Formik

I have a checkbox group (checkboxes with the same name), that I'd like to toggle them through an external button.
The parent component will map over the data and create multiple checkboxes given the data, like so:
(options.map(
option => (
<Field
name={field.name}
value={option.value}
component={CheckBoxButton}
/>
)
)}
And the CheckBoxButton is
const CheckBoxButton = ({
value,
field,
...props
}) => {
const [activeState, setActiveState] = useState(false)
return (
<div>
<Field
type="checkbox"
{...field}
{...props}
value={value}
checked={activeState}
/>
<Button
active={activeState}
onClick={() => {
setActiveState(!activeState)
}}
>
Toggle Checkbox
</Button>
</div>
)
}
Now on submission, it seems the checked={activeState} value passed to the field seemed to be ignored, nor that it triggers onChange when changed. I have tried to use setFieldValue() but since we have multiple checkboxes with the same name, it only captures the last value. To use it means I'd have to manually structure the value array and pop/add values, which seems like an overkill.
I also tried using useRef and setting ref.current.checked manually, but at no use.
Any insights on what I might be doing wrong, or how to properly set the value programmatically?
So, I managed to get a workaround that solves the problem by wrapping the button (now a div) and checkbox within the same Label, and overriding the state within the onChange event of the field. Each field would have a unique identifier id which the label binds to using htmlFor.
While a valid workaround, it would still be nice to have a programmatic way to do so.
const CheckBoxButton = ({value,field,...props}) => {
const [activeState, setActiveState] = useState(active)
const { handleChange } = useFormikContext()
const fieldId = `${field.name}-${value}`
return (
<label htmlFor={fieldId}>
<Field
id={fieldId}
type="checkbox"
{...field}
{...props}
value={value}
onChange={(event) => {
setActiveState(!activeState)
handleChange(event)
}}
className={style.checkbox}
/>
<span active={activeState} >
Toggle Checkbox
</span>
</label>
)
}

React select multiple true- comma separated value display

Is it possible to get the display of selected values as comma separated.. instead of the box with cross sign
import Select from 'react-select'
<Select
name=''
styles={customStyles}
isClearable
isMulti
/>
You can create your own custom MultiValueContainer component. To display comma separated options, we can do something like this:
render() {
const components = {
MultiValueContainer: ({ selectProps, data }) => {
const values = selectProps.value;
if (values) {
return values[values.length - 1].label === data.label
? data.label
: data.label + ", ";
} else return "";
}
};
return (
<Select
value={this.state.value}
onChange={this.handleChange}
isMulti
name="colors"
options={colourOptions}
className="basic-multi-select"
classNamePrefix="select"
components={components}
/>
);
}
here is the code sandbox link to see above code in action.
According to the React-Select docs, you can change the styles of the individual selected items.
But, they render as boxes with x buttons on them so that the user can choose to de-select any of the selected items.
I would suggest playing with the React-Select styles like this:
<Select
styles={customStyles}
/>

React Select - Multi Select custom way to display multiple options

I am looking to customize the multiselect and the way we create the display of showing selected options.
Right now, with many options selected the select component takes up a prohibitive amount of space for certain UIs. See example:
I'd like to utilize the out of the box chip display for selected options within the input, but I only want to show only a few selected options (like 3/4 max) and then add a "badge" count for the number of selected options that aren't shown in the value container in the input. The options that are selected but are past the max number of chips allowed to show in the input should show as selected within the dropdown list, while the chips that do show's values should not show in our dropdown.
I've implemented part of this with using a custom ValueContainer to show only the first few chip selections, and then adding a count of additional/"overflow" selections. I'm unsure of how I can utilize the prop hideSelectedOptions to achieve this to show selected items in the list only when my max is met without showing all of them since this prop takes a boolean.
Here's what I have so far: https://codesandbox.io/s/custom-react-select-sjtib
import React, { Component } from "react";
import Select, { components } from "react-select";
import { colourOptions } from "./docs/data";
import "./example.css";
class CustomSelect extends Component {
state = {
values: []
};
handleChange = values => {
this.setState({ values });
};
render() {
const { values } = this.state;
return (
<div>
<Select
hideSelectedOptions={values.length < 3 ? true : false}
isMulti
options={colourOptions}
onChange={this.handleChange}
value={values}
components={{ ValueContainer }}
/>
</div>
);
}
}
export default CustomSelect;
const ValueContainer = ({ children, getValue, ...props }) => {
let maxToShow = 3;
var length = getValue().length;
let displayChips = React.Children.toArray(children).slice(0, maxToShow);
let shouldBadgeShow = length > maxToShow;
let displayLength = length - maxToShow;
return (
<components.ValueContainer {...props}>
{!props.selectProps.inputValue && displayChips}
<div className="root">
{shouldBadgeShow &&
`+ ${displayLength} item${length != 1 ? "s" : ""} selected`}
</div>
</components.ValueContainer>
);
};
I would personally keep hideSelectedOptions={false} and go for styles property usage (options property to be more exact) and setting display: 'none' for the ones which shouldn't be visible:
const styles = {
option: (base, value) => {
return (shouldBeShown(value) ? { ...base } : { display: 'none'});
}
};
shouldBeShown(value) is a custom function for checking if the particular option should be shown.
In order to get option data you can use value.data.
Then you can set styles={styles} in Select component:
<Select
hideSelectedOptions={false}
isMulti
styles={styles}
onChange={this.handleChange}
options={options}
value={values}
components={{ ValueContainer }}
/>

Cannot pass the correct value when user Selects an new Option in Dropdown Component

I'm creating a new generic dropdown component for this form. I'm running into an issue where when you go to make a new selection, it sets the new value to the current value again. When I select the desired option a second time, the dropdown will then show the correct option.
Upon inspection I've noticed that when I use event.target.value, it's only returning the current (default) value I set, not the value I'm trying to select. I suspect that this is the issue.
function SelectInput (props) {
const [selectedOption, setSelectedOption] = useState(undefined);
useEffect(() => {
setSelectedOption(input.currentValue);
}, [props.currentValue])
return (
<select
name={props.inputName}
value={selectedOption}
ref={props.register}
onChange={e => setSelectedOption(e.target.value)}>
{props.options.map((option, i) => (
<option value={i+1} key={i}>{option}</option>
))}
</select>
)
};
If using e.target.value isn't the correct way to get the option the user is trying to select, I'm not sure what is. This field needs to be able to show pre-populated data (or option) but also allow the user to change the value. (In hopefully not two clicks, like it's currently behaving)
Your setup seems a little strange to me, so I have replaced your input param with standard React props. You don't need the useEffect hook and it works if you take it out:
function SelectInput(props) {
const [selectedOption, setSelectedOption] = useState(props.defaultVal);
return (
<select
name={input.inputName}
value={selectedOption}
ref={input.register}
onChange={e => setSelectedOption(e.target.value)}
>
{input.options.map((option, i) => (
<option value={i + 1} key={i}>
{option}
</option>
))}
</select>
);
}
ReactDOM.render(
<SelectInput options={input.options} defaultVal={3} />,
document.getElementById("root")
);
Possibly the 'currentValue' you were trying to set did not correlate to an option value (e.g. number).
https://codesandbox.io/s/react-select-input-fn4to

Resources