Programmatically select an option with react-select - javascript

I have a basic understanding of React. I'm using react-select and I want to programmatically select an option. For example, with the code below, how to select option B on clicking the button?
This page mentions a setValue function, but I don't understand how to use it. I don't know what is a "ref" in React and how to use it, and I found similar questions on SO with answers assuming this knowledge.
import { useState } from "react";
import Select from "react-select";
const options = [
{ value: "A", label: "A" },
{ value: "B", label: "B" }
];
export default function App() {
const [selectedOption, setSelectedOption] = useState("A");
const handleChange = (value) => {
setSelectedOption(value);
};
return (
<div className="App">
<Select
value={selectedOption}
onChange={handleChange}
options={options}
/>
<button onClick={() => ????????}>Select B</button>
</div>
);
}

You can use the following code.
import { useState } from "react";
import Select from "react-select";
const options = [
{ value: "A", label: "A" },
{ value: "B", label: "B" }
];
export default function App() {
const [selectedOption, setSelectedOption] = useState(options[0]);
const handleChange = (value) => {
setSelectedOption(value);
};
return (
<div className="App">
<Select
value={selectedOption}
onChange={handleChange}
options={options}
/>
<button onClick={() => setSelectedOption(options[1])}>Select B</button>
</div>
);
}
React-Select is different with Select from Material UI. React-Select receives the object of options and set, display the value according to the object.

Related

onChange react-select multiple options

I need to detect if I tipe into a searchable react-select. According to the official documentation first of all I have to pass isMulti prop in order to select more than an option.
The actual built-in onChange detects changes only when I select an option, and not when I type into the box. I need it because I have to call an API if I type into that input box.
Here is My select:
<Select
options={myOptions}
isMulti
loadingIndicator={true}
styles={selectStyle}
onChange={(e) => console.log(`e`, e)}
/>
Actually onChange logs me an array with the options selected. How can I change that for example if I type "fo" then I have "fo"? Is there any option or way to do so?
Yes, we have async select option to load data from API when user type.
Below I have attached the code for you documented in their official website.
https://react-select.com/home#async
import { useState } from "react";
import AsyncSelect from "react-select/async";
const colourOptions = [
{ label: "Oranage", value: "orange" },
{ label: "Yellow", value: "yellow" },
{ label: "Blue", value: "blue" }
];
const SelectOption = () => {
const [inputValue, setInputValue] = useState("");
const filterColors = (inputValue) => {
return colourOptions.filter((i) =>
i.label.toLowerCase().includes(inputValue.toLowerCase())
);
};
const promiseOptions = (inputValue, callback) => {
setTimeout(() => {
callback(filterColors(inputValue));
}, 1000);
};
const handleChange = (newValue) => {
const inputValue = newValue.replace(/\W/g, "");
setInputValue(inputValue);
return inputValue;
};
return (
<AsyncSelect
cacheOptions
defaultOptions
loadOptions={promiseOptions}
onInputChange={handleChange}
/>
);
};
export default SelectOption;
There is no onKeyDown props available in react-select's documentation.
What you can do is something like below:
class App extends Component {
onKeyUp = () => {
console.log("I see");
// Your rest code
};
render() {
return (
<div onKeyUp={this.onKeyUp} className="App">
<Select
options={myOptions}
isMulti
loadingIndicator={true}
styles={selectStyle}
onChange={(e) => console.log(`e`, e)}
/>
</div>
);
}
}

how to set first value of array as default in cascading dropdown in react hooks

I am using material UI to list dropdown value I have a hub,Country and account dropdown fields i want to set the first value of the array object to select initial value selected.
data file:
export const dataHub = [
{ name: 'Western Europe', hubId: 1 },
{ name: 'IMMEA', hubId: 2 },
]
export const dataCountry = [
{ name: 'France', countryId: 1, hubId: 1 },
{ name: 'Germany', countryId: 2, hubId: 1 },
{ name: 'Italy', countryId: 3, hubId: 1 },
{ name: 'Spain', countryId: 4, hubId: 1 },
{ name: 'Sweden', countryId: 5, hubId: 1 },
{ name: 'Switzerland', countryId: 6, hubId: 2 },
{ name: 'Uk', countryId: 7, hubId: 1 },
]
export const dataAccount = [
{name:'Telco-channel',panterName:'',accountId:1,countryId:1},
{name:'Consumer-Online',panterName:'',accountId:2,countryId:2},
{name:'Education-Retail',panterName:'',accountId:3,countryId:2},
{name:'Non-Trade',panterName:'',accountId:4,countryId:2},
{name:'Telco-channel',panterName:'',accountId:5,countryId:3},
{name:'Commercial-channel',panterName:'',accountId:6,countryId:4},
{name:'Consumer-Retail',panterName:'',accountId:7,countryId:5},
{name:'Commercial-Online',panterName:'',accountId:8,countryId:6},
{name:'Non-Trade',panterName:'',accountId:9,countryId:6},
{name:'Education-Online',panterName:'',accountId:10,countryId:1},
{name:'Consumer-Retail',panterName:'',accountId:11,countryId:2},
{name:'Telco-channel',panterName:'',accountId:12,countryId:2},
{name:'Commercial-channel',panterName:'',accountId:13,countryId:3},
{name:'Consumer-Online',panterName:'',accountId:14,countryId:3},
{name:'Consumer-Online',panterName:'',accountId:15,countryId:4},
{name:'Consumer-Retail',panterName:'',accountId:16,countryId:4},
{name:'Non-Trade',panterName:'',accountId:17,countryId:4},
{name:'Telco-channel',panterName:'',accountId:18,countryId:4},
{name:'Consumer-Online',panterName:'',accountId:19,countryId:5},
{name:'Commercial-Retail',panterName:'',accountId:20,countryId:7},
{name:'Consumer-Online',panterName:'',accountId:21,countryId:7},
{name:'Education-Online',panterName:'',accountId:22,countryId:7},
{name:'Education-Retial',panterName:'',accountId:23,countryId:7},
{name:'Non-Trade',panterName:'',accountId:24,countryId:7},
]
below is the component rendering dropdown fields
import React, { useState, useEffect } from 'react'
import { dataHub, dataCountry, dataAccount } from "../../constants/defaultValues";
import SelectMenu from '../../components/SelectMenu';
const defaultItemHub = { name: 'Select Hub ...' };
const defaultItemCountry = { name: 'Select Country ...' };
const defaultItemAccount = { name: 'Select Account ...' };
const Filters = () => {
const [hub, setHub] = useState('')
const [country, setCountry] = useState('')
const [account, setAccount] = useState('')
const [countries, setCountries] = useState(dataCountry)
const [accounts, setAcconts] = useState(dataAccount)
useEffect(() => {
const defaultHub = sort(dataHub)[0]
const defaultCountry = sort(dataCountry).filter(country => country.hubId === defaultHub.hubId)[0];
let defaultAccount = sort(dataAccount).filter(account => account.countryId === defaultCountry.countryId)[0];
setHub(defaultHub)
setCountry(defaultCountry)
setAccount(defaultAccount)
}, [])
const hubChange = (event) => {
const hub = event.target.value;
const countries = dataCountry.filter(country => country.hubId === hub.hubId);
setHub(hub)
setCountries(countries)
setCountry('')
setAccount('')
}
const countryChange = (event) => {
const country = event.target.value;
const accounts = dataAccount.filter(account => account.countryId === country.countryId);
setCountry(country)
setAcconts(accounts)
setAccount('')
}
const accountChange = (event) => {
setAccount(event.target.value);
}
const hasHub = hub && hub !== defaultItemHub;
const hasCountry = country && country !== defaultItemCountry;
//console.log("defaultHub",defaultHub)
return (
<div className="container">
<div className="d-flex mr-1 justify-content-center align-items-center">
<SelectMenu field={"Hub"} value={hub} options={dataHub} fieldtype={"dropdown"} onChange={hubChange} />
<SelectMenu field={"Country"} value={country} disabled={!hasHub} options={countries} fieldtype={"dropdown"} onChange={countryChange} />
<SelectMenu field={"Account"} value={account} disabled={!hasCountry} options={accounts} fieldtype={"dropdown"} onChange={accountChange} />
</div>
</div>
)
}
export default Filters
the selectMenu component, I am passing props required props for the component below
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import InputLabel from '#material-ui/core/InputLabel';
import MenuItem from '#material-ui/core/MenuItem';
import FormControl from '#material-ui/core/FormControl';
import Select from '#material-ui/core/Select';
import TextField from '#material-ui/core/TextField';
const useStyles = makeStyles((theme) => ({
formControl: {
margin: theme.spacing(2),
minWidth: 180,
},
selectEmpty: {
marginTop: theme.spacing(2),
},
}));
export default function SelectMenu({ field, options, value, disabled, fieldtype, onChange }) {
const classes = useStyles();
const handleChange = (event) => {
onChange(event)
};
// When the field is a dropdown
if (fieldtype === "dropdown") {
return (
<div>
<FormControl variant="outlined" className={classes.formControl}>
<InputLabel id="demo-simple-select-outlined-label">{field}</InputLabel>
<Select
labelId="demo-simple-select-outlined-label"
id="demo-simple-select-outlined"
value={value || ''}
onChange={handleChange}
label={field}
disabled={disabled}
>
{
options.map((element, key) => {
return (
<MenuItem key={key} value={element}>{element.name}</MenuItem>
)
})
}
</Select>
</FormControl>
</div>
);
}
else {
// When the field is a Integer and Prepopulated
if (options != null) {
return (
<div>
<FormControl variant="outlined" className={classes.formControl}>
<TextField
id="outlined-read-only-input"
label={field}
value={options[0].value}
defaultValue="Hello World"
InputProps={{
readOnly: true,
}}
variant="outlined"
/>
</FormControl>
</div>
)
}
//When the field is a Integer and a Input from the user
else {
return (
<div>
<FormControl variant="outlined" className={classes.formControl}>
<TextField id="outlined-basic"
onChange={handleChange}
label={field} variant="outlined" />
</FormControl>
</div>
)
}
}
}
Can anyone help me what wrong i am doing,I am not able to set the default value in the dropdown.
enter image description here
I feel there are couple of reasons which might be causing this issue.
Make sure that, default value should present in actual options. i.e default country should be one among countries list then only default value gets picked by material UI component.
As per material UI docs, If the value is an object it must have reference equality with the option in order to be selected. If the value is not an object, the string representation must match with the string representation of the option in order to be selected. So you should define equality so that value property of Select will get matched with value property of MenuItem and then it gets picked as default value.
Try using defaultValue instead of value in <Select> tag.

Select with value prop inside of Form.Item won't reflect any change of that value prop

I'm having trouble with antd forms in regard to Select input. I have two Select inputs and I need the second input to "reset" to the first option when the first input changes value.
I need to keep track of each Select value with React.useState because —in my real code— those values are used to make a request to a backend and re-populate other Select inputs but the first one, and each Select have a different amount of options, thus is desirable that they get "reset" to the first option.
How can I achieve what I'm looking for?
Since you decide to control the input field with value and onChange,
You don't need the Form name, remove it.
Then set the first hander, check if the value changed to decide whether set the second to default or not.
import React from "react";
import ReactDOM from "react-dom";
import { Select, Form } from "antd";
import "antd/dist/antd.css";
const fieldA = [{ value: 1, text: "Hello" }, { value: 2, text: "World" }];
const fieldB = [{ value: 1, text: "A" }, { value: 2, text: "B" }];
const App = () => {
const [valueA, setValueA] = React.useState(null);
const [valueB, setValueB] = React.useState(null);
const setFieldA = (value: number) => {
if (valueA !== value) {
setValueB(null);
}
setValueA(value);
};
const setFieldB = (value: number) => {
setValueB(value);
};
return (
<Form layout="vertical">
<Form.Item label="Field A">
<Select value={valueA} onChange={setFieldA}>
{fieldA.map(field => (
<Select.Option value={field.value}>{field.text}</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item label="Field B">
<Select value={valueB} onChange={setFieldB}>
{fieldB.map(field => (
<Select.Option value={field.value}>{field.text}</Select.Option>
))}
</Select>
</Form.Item>
<div>
Field A "real" value: {valueA}
<br />
Field B "real" value: {valueB}
</div>
</Form>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
If you add Select into the Form and Form.Item and set a name for Form.Item, the Select is completely controlled by the Form. You need to use the Form's api to control the Select or simply remove the name
import React from "react";
import ReactDOM from "react-dom";
import { Select, Form } from "antd";
import "antd/dist/antd.css";
const fieldA = [{ value: 1, text: "Hello" }, { value: 2, text: "World" }];
const fieldB = [{ value: 1, text: "A" }, { value: 2, text: "B" }];
const App = () => {
const [myvalues, setMyvalues] = React.useState({ valueA: 1, valueB: 1 });
const setFieldA = (value: number) => {
setMyvalues({ valueA: value, valueB: 1 });
form.setFieldsValue({ valueA: value, valueB: 1 });
};
const setFieldB = (value: number) => {
setMyvalues({ ...myvalues, valueB: value });
form.setFieldsValue({ ...myvalues, valueB: value });
};
const [form] = Form.useForm();
return (
<Form layout="vertical" form={form} initialValues={myvalues}>
<Form.Item name="valueA" label="Field A" shouldUpdate>
<Select value={myvalues.valueA} onChange={setFieldA}>
{fieldA.map(field => (
<Select.Option value={field.value}>{field.text}</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item name="valueB" label="Field B" shouldUpdate>
<Select value={myvalues.valueB} onChange={setFieldB}>
{fieldB.map(field => (
<Select.Option value={field.value}>{field.text}</Select.Option>
))}
</Select>
</Form.Item>
<div>
Field A "real" value: {myvalues.valueA}.<br />
Field B "real" value: {myvalues.valueB}
</div>
</Form>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
You can check here CodeSandBox. Hope it helps

React - how to use hooks to hide or show a component based on an onChange event

I'm trying to figure out how to use react hooks to hide or show a component based on an onChange event (a selected option being selected in a form).
I have a component called Animal, which will be hidden until someone selects 'animals' from a select menu in a form.
This is what I have tried to make:
import React, { useState, useEffect } from "react";
import useForm from "react-hook-form";
import { withRouter } from "react-router-dom";
import Select from "react-select";
import Animal from "./tips/Animal";
const specialFeatures = [
{ value: "animals", label: "Animals" },
{ value: "none", label: "None of these apply" }
];
const Method = props => {
const { register, handleSubmit, setValue, errors, reset } = useForm();
const [valuesSpecialFeatures, setSpecialFeatures] = useState([]);
const [showAnimal, setShowAnimal] = useState(false);
const handleMultiChangeSpecialFeatures = selectedOption => {
setValue("specialFeatures", selectedOption, true);
setSpecialFeatures(selectedOption);
if selectedOption === 'animals' setAnimal(!<Animal />)
};
return (
<div>
<form onSubmit={handleSubmit(onSubmit)}>
<label>Does this proposal incldue any of these features?</label>
<Select
className="reactSelect"
name="specialFeatures"
placeholder="Select at least one"
value={valuesSpecialFeatures}
options={specialFeatures}
onChange={handleMultiChangeSpecialFeatures}
isMulti
/>
{ showAnimal && "animals" <Animal /> }
<input type="submit" value="next" />
</form>
</div>
);
};
export default withRouter(Method);
I'm trying to test if the form field named specialFeatures has a selectedOption that includes the value 'animals', then if it does, I want to display the Animal component beneath that field.
This attempt is clearly incorrect, but I can't see how to set the useEffect to toggle visibility.
First of all you need to set showAnimal state to a boolean and then use that to either show or hide the component:
const Method = props => {
const { register, handleSubmit, setValue, errors, reset } = useForm();
const [valuesSpecialFeatures, setSpecialFeatures] = useState([]);
const [showAnimal, setShowAnimal] = useState(false);
const handleMultiChangeSpecialFeatures = selectedOption => {
setValue("specialFeatures", selectedOption, true);
setSpecialFeatures(selectedOption);
setShowAnimal(selectedOption.some(option => option.value === "animals")); // Toggle 'showAnimal'
};
return (
<div>
<form onSubmit={handleSubmit(onSubmit)}>
<label>Does this proposal incldue any of these features?</label>
<Select
className="reactSelect"
name="specialFeatures"
placeholder="Select at least one"
value={valuesSpecialFeatures}
options={specialFeatures}
onChange={handleMultiChangeSpecialFeatures}
isMulti
/>
{showAnimal && <Animal />} // Render component based on the toggle
<input type="submit" value="next" />
</form>
</div>
);
};
There's a simpler alternative though, which doesn't involve setting the value to the state, you can just derive it during render instead:
const Method = props => {
const { register, handleSubmit, setValue, errors, reset } = useForm();
const [valuesSpecialFeatures, setSpecialFeatures] = useState([]);
const handleMultiChangeSpecialFeatures = selectedOption => {
setValue("specialFeatures", selectedOption, true);
setSpecialFeatures(selectedOption);
};
// Derive the value based on the value of `valuesSpecialFeatures`
const isAnimalSelected = valuesSpecialFeatures.some(
option => option.value === "animals"
);
return (
<div>
<form onSubmit={handleSubmit(onSubmit)}>
<label>Does this proposal incldue any of these features?</label>
<Select
className="reactSelect"
name="specialFeatures"
placeholder="Select at least one"
value={valuesSpecialFeatures}
options={specialFeatures}
onChange={handleMultiChangeSpecialFeatures}
isMulti
/>
{isAnimalSelected && <Animal />} // Use derived value to render component
<input type="submit" value="next" />
</form>
</div>
);
};

How to implement multiple checkbox using react hook

I want to implement multiple checkboxes on my HTML page using react-hook.
I tried implementing using this URL: https://medium.com/#Zh0uzi/my-concerns-with-react-hooks-6afda0acc672. In the provided link it is done using class component and working perfectly but whenever I am using React hook setCheckedItems to update checkbox checked status it's not re-rendering the view.
The very first time the view is rendering and console.log() is printing from Checkbox component. After clicking on checkbox function handleChange gets called and checkedItems updates the value but the view is not rendering again (no console.log() printing). And {checkedItems.get("check-box-1")} is also not printing any value.
Below is my sample code.
CheckboxExample :
import React, { useState } from 'react';
import Checkbox from '../helper/Checkbox';
const CheckboxExample = () => {
const [checkedItems, setCheckedItems] = useState(new Map());
const handleChange = (event) => {
setCheckedItems(checkedItems => checkedItems.set(event.target.name, event.target.checked));
console.log("checkedItems: ", checkedItems);
}
const checkboxes = [
{
name: 'check-box-1',
key: 'checkBox1',
label: 'Check Box 1',
},
{
name: 'check-box-2',
key: 'checkBox2',
label: 'Check Box 2',
}
];
return (
<div>
<lable>Checked item name : {checkedItems.get("check-box-1")} </lable> <br/>
{
checkboxes.map(item => (
<label key={item.key}>
{item.name}
<Checkbox name={item.name} checked={checkedItems.get(item.name)} onChange={handleChange} />
</label>
))
}
</div>
);
}
export default Example;
Checkbox:
import React from 'react';
const Checkbox = ({ type = 'checkbox', name, checked = false, onChange }) => {
console.log("Checkbox: ", name, checked);
return (<input type={type} name={name} checked={checked} onChange={onChange} /> )
}
export default Checkbox;
I don't think using a Map to represent the state is the best idea.
I have implemented your example using a plain Object and it works:
https://codesandbox.io/s/react-hooks-usestate-xzvq5
const CheckboxExample = () => {
const [checkedItems, setCheckedItems] = useState({}); //plain object as state
const handleChange = (event) => {
// updating an object instead of a Map
setCheckedItems({...checkedItems, [event.target.name] : event.target.checked });
}
useEffect(() => {
console.log("checkedItems: ", checkedItems);
}, [checkedItems]);
const checkboxes = [
{
name: 'check-box-1',
key: 'checkBox1',
label: 'Check Box 1',
},
{
name: 'check-box-2',
key: 'checkBox2',
label: 'Check Box 2',
}
];
return (
<div>
<lable>Checked item name : {checkedItems["check-box-1"]} </lable> <br/>
{
checkboxes.map(item => (
<label key={item.key}>
{item.name}
<Checkbox name={item.name} checked={checkedItems[item.name]} onChange={handleChange} />
</label>
))
}
</div>
);
}
EDIT:
Turns out a Map can work as the state value, but to trigger a re-render you need to replace the Map with a new one instead of simply mutating it, which is not picked by React, i.e.:
const handleChange = (event) => {
// mutate the current Map
checkedItems.set(event.target.name, event.target.checked)
// update the state by creating a new Map
setCheckedItems(new Map(checkedItems) );
console.log("checkedItems: ", checkedItems);
}
but in this case, I think there is no benefit to using a Map other than maybe cleaner syntax with .get() and .set() instead of x[y].
As an alternative to Map, you might consider using a Set. Then you don't have to worry about initially setting every item to false to mean unchecked. A quick POC:
const [selectedItems, setSelectedItems] = useState(new Set())
function handleCheckboxChange(itemKey: string) {
// first, make a copy of the original set rather than mutating the original
const newSelectedItems = new Set(selectedItems)
if (!newSelectedItems.has(itemKey)) {
newSelectedItems.add(itemKey)
} else {
newSelectedItems.delete(itemKey)
}
setSelectedItems(newSelectedItems)
}
...
<input
type="checkbox"
checked={selectedItems.has(item.key)}
onChange={() => handleCheckboxChange(item.key)}
/>
Seems a bit of a long way round but if you spread the map out and apply it to a new Map your component will re-render. I think using a Object reference instead of a Map would work best here.
const {useState} = React
const Mapper = () => {
const [map, setMap] = useState(new Map());
const addToMap = () => {
const RNDM = Math.random().toFixed(5)
map.set(`foo${RNDM}`, `bar${RNDM}`);
setMap(new Map([...map]));
}
return (
<div>
<ul>
{[...map].map(([v, k]) => (
<li key={k}>
{k} : {v}
</li>
))}
</ul>
<button onClick={addToMap}>add to map</button>
</div>
);
};
const rootElement = document.getElementById("react");
ReactDOM.render(<Mapper />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
As a supplement to using a single object to hold the state of numerous items, the updates will not occur as expected if updating multiple items within a single render. Newer commits within the render cycle will simply overwrite previous commits.
The solution to this is to batch up all the changes in a single object and commit them all at once, like so:
// An object that will hold multiple states
const [myStates, setMyStates] = useState({});
// An object that will batch all the desired updates
const statesUpdates = {};
// Set all the updates...
statesUpdates[state1] = true;
statesUpdates[state2] = false;
// etc...
// Create a new state object and commit it
setMyStates(Object.assign({}, myStates, statesUpdates));
export default function Input(props) {
const {
name,
isChecked,
onChange,
index,
} = props;
return (
<>
<input
className="popup-cookie__input"
id={name}
type="checkbox"
name={name}
checked={isChecked}
onChange={onChange}
data-action={index}
/>
<label htmlFor={name} className="popup-cookie__label">{name}</label>
</>
);
}
const checkboxesList = [
{name: 'essential', isChecked: true},
{name: 'statistics', isChecked: false},
{name: 'advertising', isChecked: false},
];
export default function CheckboxesList() {
const [checkedItems, setCheckedItems] = useState(checkboxesList);
const handleChange = (event) => {
const newCheckboxes = [...checkedItems];
newCheckboxes[event.target.dataset.action].isChecked = event.target.checked;
setCheckedItems(newCheckboxes);
console.log('checkedItems: ', checkedItems);
};
return (
<ul className="popup-cookie-checkbox-list">
{checkboxesList.map((checkbox, index) => (
<li className="popup-cookie-checkbox-list__item" key={checkbox.name}>
<Input
id={checkbox.name}
name={checkbox.name}
isChecked={checkbox.isChecked}
onChange={handleChange}
index={index}
/>
</li>
))}
</ul>
);
}```

Categories

Resources