MultiSelect with formState issue on form Submit - javascript

I am using MultiSelect inside a form and wanted to set the formState with the selected values using onChange.
At present, the below code passes the default null value for permission_sets on form submit.
Can someone take a look and let me know how to update the value of permission_sets inside formState from onChange on dropdown selections. This will pass the actual selected values on the form Submit.
const formState = {
permission_sets: "",
}
function updateFormState(key, value) {
formState[key] = value;
}
function App() {
const [permission_sets, set_permission_sets] = useState([]);
return (
<Form.Group>
<Form.Label>permission_sets</Form.Label>
<MultiSelect
options={[
{ label: "Operations", value: "Operations" },
{ label: "ReadOnlyAccess", value: "ReadOnlyAccess" },
{ label: "Dba", value: "Dba"},
]}
id="permission_sets"
labelledBy="Select"
value={permission_sets}
onChange={set_permission_sets}
/>
</Form.Group>
<Button onClick={validate}>Submit Request</Button>
)}

Related

Using react-select with multiple inputs

I have multiple react-select inputs, each have their own separate options array. The issue i'm having is I'm now sure how to properly store the output of each select input.
I want to use this select output to POST to my backend but i'm unsure how to do it all with a single handler function.
This is what I have so far, i have 2 paragraphs to just output the appropriate result from the select fields but i can't seem to get it working.
This is the codesandbox i have:
https://codesandbox.io/s/busy-yonath-rlj9e?file=/src/App.js
In your code you are using the useState() hook and everytime a user selects an option, you are setting your state variable to the selected value.
The problem is that everytime you run the setSelectOptions({ e }) function, you are overwriting the existing data with the value of 'e'.
What you can do is:
Create a selectHandler function that takes in 2 arguments (the new value and the value it corresponds to in the state variable)
The code will look something like this:
import "./styles.css";
import Select from "react-select";
import { useEffect, useState } from "react";
export default function App() {
const [selectOptions, setSelectOptions] = useState({
brand: "",
model: "",
color: "",
bodyType: "",
fuelType: "",
transmission: "",
location: ""
});
const brandOptions = [
{ value: "bmw", label: "Bmw" },
{ value: "audi", label: "Audi" },
{ value: "toyota", label: "Toyota" },
{ value: "nissan", label: "Nissan" }
];
const transmissionOptions = [
{ value: "automatic", label: "Automatic" },
{ value: "manual", label: "Manual" }
];
useEffect(() => console.log(selectOptions), [selectOptions])
const handleChange = (e, type) => {
setSelectOptions((previousState) => ({
...previousState,
[type]: e.value,
}));
};
return (
<div className="App">
selected brand: {selectOptions.brand}
<br />
selected transmission:{selectOptions.transmission}
<div className="mb-2" style={{ width: "40%", margin: "0 auto" }}>
<Select
value={selectOptions.brand}
onChange={(e) => handleChange(e, "brand")}
placeholder="Select brand"
options={brandOptions}
/>
<Select
value={selectOptions.transmission}
onChange={(e) => handleChange(e, "transmission")}
placeholder="Select transmission"
options={transmissionOptions}
/>
</div>
</div>
);
}
Just as an explanation, all I am doing in the setSelectOptions() function is passing in the previous values of the state variable and updating the value coinciding to the select field.
Note: Insert this code into your project, I ran it and it worked so let me know if it did help!

Get value of select menus when clicking reset button React

I have a set of select menus and I need to find out the values for all of them when I reset them using reset buttons.
The problem is this only works on change event for options and I can't make it work on reset buttons on the first click as it doesn't detect the change.
Code sample here:
https://stackblitz.com/edit/react-rmp8kf
import React from 'react';
import { useState } from 'react';
import uuid from 'react-uuid';
export default function Select() {
const [value, setValue] = useState({
select1: '',
select2: '',
});
const selectOptions = [
{
options: [
{
text: 'All',
value: '0',
},
{
text: 'Blue',
value: '1',
},
{
text: 'Yellow',
value: '2',
},
{
text: 'Green',
value: '3',
},
],
},
{
options: [
{
text: 'All',
value: '0',
},
{
text: 'Black',
value: '1',
},
{
text: 'White',
value: '2',
},
],
},
];
const handleOnChange = (e) => {
const valueSelected = e.target.value;
setValue({
...value,
[e.target.name]: valueSelected,
});
printAllSelectValues();
};
const resetAllSelections = (e) => {
e.preventDefault();
setValue({
select1: '',
select2: '',
});
printAllSelectValues();
};
const resetSelection = (e) => {
e.preventDefault();
setValue({
...value,
[e.target.dataset.selectName]: '',
});
printAllSelectValues();
};
const printAllSelectValues = () => {
const selectMenus = document.querySelectorAll('select');
selectMenus.forEach((select) =>
console.log(select.name + '=' + select.value)
);
};
return (
<form>
<div>
<label>
<select
name="select1"
value={value.select1}
onChange={handleOnChange}
>
{selectOptions[0].options.map((option) => (
<option value={option.value} key={uuid()}>
{option.text}
</option>
))}
</select>
</label>
<button data-select-name="select1" onClick={resetSelection}>
Reset
</button>
</div>
<div>
<label>
<select
name="select2"
value={value.select2}
onChange={handleOnChange}
>
{selectOptions[1].options.map((option) => (
<option value={option.value} key={uuid()}>
{option.text}
</option>
))}
</select>
</label>
<button data-select-name="select2" onClick={resetSelection}>
Reset
</button>
</div>
<button onClick={resetAllSelections}>Reset All</button>
</form>
);
}
The stackblitz sandbox you linked seems to do exactly what you need to. You are getting both values correctly when:
You select any value in any of the 2 select elements
You reset any of the select values individually by using the reset button on the side of each select element
You reset both values at once by using the "Reset All" button
What is the problem? Do you want to get the updated values ?
UPDATE
Okey. So react has the nature that every state update is async, meaning that you need to wait for a state update to happen to use its updated values. Now, you cannot use promises or async/await to do this because react is built intentionally this way and gives you the tools to do so. So you need to use the useEffect hook for this.
https://stackblitz.com/edit/react-bekzpz
Note: worth mentioning that you don't need to grab the data from the HTML elements but in case you want to manipulate DOM elements in react, you are not supposed to do it using the document but by using the useRef hook

React Select Unable to Remove Items From State Array

I am using React Select (https://react-select.com/home) which contains a bunch of options and the onChange handler will identify the selected items and push it into a State array.
The issue im running into is how to remove unselected items from the State array:
import Select from 'react-select'
const [selectedTeams, setSelectedTeams] = useState([]);
function manageSelectedTeams(event) {
console.log('function triggered')
setSelectedTeams([])
event.forEach((team) => {
console.log(team.value)
setSelectedTeams(() => [...selectedTeams, team.value])
})
}
data = [
{
label: "Example"
value: "example"
},
{
label: "Example"
value: "example"
},
{
label: "Example"
value: "example"
},
]
return (
<Select isMulti options={data} onChange={(e) => manageSelectedTeams(e)} closeMenuOnSelect={false} placeholder={"Teams will auto populate here once Location is defined above"} />
)
How would I tackle removing items from selectedTeams when a particular option is unselected/unticked
TIA
react-select handles the insert and delete for you so do not need to create a separate logic for it. When we use onChange the array of selected objects could be one possible parameter. You can refer to the same in the documentation. https://react-select.com/props
Thus you need to update your code as follows:
function manageSelectedTeams(data) {
let finalValueList = data.map((item) => item.value);
console.log(finalValueList);
setSelectedTeams(finalValueList);
}
return (
<Select
isMulti
options={data}
onChange={manageSelectedTeams} //UPDATED
closeMenuOnSelect={false}
placeholder={
"Teams will auto populate here once Location is defined above"
}
/>
);

Passing value to state using react-select

I'm new to react and trying to learn on my own. I started using react-select to create a dropdown on a form and now I'm trying to pass the value of the option selected. My state looks like this.
this.state = {
part_id: "",
failure: ""
};
Then in my render
const {
part_id,
failure
} = this.state;
My form looks has 2 fields
<FormGroup>
<Label for="failure">Failure</Label>
<Input
type="text"
name="failure"
placeholder="Failure"
value={failure}
onChange={this.changeHandler}
required
/>
</FormGroup>
<FormGroup>
<Label for="part_id">Part</Label>
<Select
name="part_id"
value={part_id}
onChange={this.changeHandler}
options={option}
/>
</FormGroup>
the changeHandler looks like this
changeHandler = e => {
this.setState({ [e.target.name]: e.target.value });
};
The change handler works fine for the input but the Select throws error saying cannot read property name. I went through the API docs and came up with something like this for the Select onChange
onChange={part_id => this.setState({ part_id })}
which sets the part_id as a label, value pair. Is there a way to get just the value? and also how would I implement the same with multiselect?
The return of react-select onChange event and the value props both have the type as below
event / value:
null | {value: string, label: string} | Array<{value: string, label: string}>
So what the error means is that you can't find an attribute of null (not selected), or any attributes naming as name (you need value or label)
For multiple selections, it returns the sub-list of options.
You can find the related info in their document
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' },
];
Update
For your situation (single selection)
option having type as above
const option = [
{value: '1', label: 'name1'},
{value: '2', label: 'name2'}
]
state save selected value as id
changeHandler = e => {
this.setState({ part_id: e ? e.value : '' });
};
pick selected option item via saved id
<Select
name="part_id"
value={option.find(item => item.value === part_id)}
onChange={this.changeHandler}
options={option}
/>
For multiple selections
state save as id array
changeHandler = e => {
this.setState({ part_id: e ? e.map(x => x.value) : [] });
};
pick via filter
<Select
isMulti // Add this props with value true
name="part_id"
value={option.filter(item => part_id.includes(item.value))}
onChange={this.changeHandler}
options={option}
/>
onChange function is a bit different in react-select
It passes array of selected values, you may get first one like
onChange={([selected]) => {
// React Select return object instead of value for selection
// return { value: selected };
setValue(selected)
}}
I have tried the above solutions but some of these solutions does update the state but it doesn't gets rendered on the Select value instantly.
Herewith a demo example:
this.state = {
part_id: null,
};
handleUpdate = (part_id) => {
this.setState({ part_id: part_id.value }, () =>
console.log(`Option selected:`, this.state.part_id)
);
};
const priceOptions = [
{ value: '999', label: 'Item One' },
{ value: '32.5', label: 'Item Two' },
{ value: '478', label: 'Item Three' }
]
<Select
onChange={this.handleUpdate}
value={priceOptions.find(item => item.value === part_id)}
options={priceOptions}
placeholder={<div>Select option</div>}
/>

How to Create an AutoComplete in React

What I have here is a function where I call the codigo, and the nombre, in the DB
  table registrations. What I want to achieve is that the digital code that is like an autocomplete to fill in the name when you select the code.
enter image description here
class Matriculas extends Component {
state = {
status: "initial",
data: []
}
componentDidMount = () => {
this. getInfo()
}
getInfo= async () => {
try {
const response = await getAll('matriculas')
console.log(response.data)
this.setState({
status: "done",
data: response.data
});
} catch (error) {
this.setState({
status: "error"
});
}
};
render() {
const data = [...this.state.data];
return (
<Container>
<RowContainer margin="1px" >
<ColumnContainer margin="10px">
<h3>Info</h3>
<label>Codigo</label>
<Input
width='150px'
type="text"
placeholder="Digite el codigo"
value={data.codigo } ref="codigo" />
<label>Nombre</label>
<Input
width='150px'
type="text"
placeholder="Nombre completo"
value={data.nombre} />
</ColumnContainer>
</RowContainer>
</Container>
)
}
};
export default Matriculas;
What you most likely want to use is react-select
You can pass options to the select (which would be your names) and it will return values that match whatever you type in the search bar.
import Select from 'react-select'
const options = [
{ value: 'mike', label: 'Mike' },
{ value: 'john', label: 'John' },
{ value: 'vanessa', label: 'Vanessa' }
]
const MyComponent = () => (
<Select options={options} />
)
So you can take that example, and the examples in the link, and put it in your code:
import Select from 'react-select'
<Container>
<RowContainer margin="1px" >
<ColumnContainer margin="10px">
<h3>Info</h3>
<label>Codigo</label>
<Input
width='150px'
type="text"
placeholder="Digite el codigo"
value={data.codigo } ref="codigo" />
<label>Nombre</label>
<Select
value={this.state.nameValue}
onChange={event => {this.setState({nameValue: e.value})}
options={options} />
</ColumnContainer>
</RowContainer>
</Container>
When using onChage, it returns an event, which has the value of the selected name. You can use that to set the state's nameValue, and then use that name value in the rest of your component as well
Once you get this up and running, it also worth looking at the async select, which allows you to give an async function that returns values (your getInfo function, for example)
-- edit --
If you want to define the onChange event elsewhere, it would look like this:
handleChange = event => {
// event.value will be the value of the select
this.setState({optionSelected: event.value});
}
and then in your onChange, tell it that is the function you want but do not invoke it (don't write it with parentheses):
<Select
value={this.state.optionSelected}
onChange={this.handleChange}
options={options} />

Categories