How to remove null selected values from a react-select multi select - javascript

I have been trying to set up react-select but when I enable isMulti there is always two selected blank values in the selection box.
I have tried setting default values, using state to control the Select but it keeps showing these two blank values when I load the page. Here are some code snippets of the things I have tried:
<Select
isMulti
/>
<Select
isMulti
defaultValue={[]}
/>
<Select
isMulti
options={majors().map((element: any) => {
return { value: element[2], label: element[2] }
})}
/>
<Select
isMulti
defaultValue={[]}
options={majors().map((element: any) => {
return { value: element[2], label: element[2] }
})}
/>
interface Option {
value: String,
label: String
}
let def : Option[] = []
<Select
isMulti
defaultValue={def}
options={majors().map((element: any) => {
return { value: element[2], label: element[2] }
})}
/>

Not entirely sure the reason for this, but what ended up fixing the problem was wrapping the <Select> inside of a <div>.
This did the trick:
<div>
<Select
isMulti
defaultValue={[]}
options={majors().map((element: any) => {
return { value: element[2], label: element[2] }
})}
/>
</div>

Related

React-select multiple selects on one page

I am a bit confused, here is an example with a couple of select inputs that have the same state, please check here: https://stackblitz.com/edit/get-selected-by-value-multi-select-react-agamk4?file=src/App.js so please:
How can I make it so when I select an option the value does not apply to the rest of the select inputs?
How would you put the values in the store for each of the selects?
Do I need multiple stores?
For more clarity, here is a screenshot: https://www.awesomescreenshot.com/image/19798040?key=bb839c650c93b436066e03d33d5515b0 I hope this makes sense? What would be the best approach? Thank you.
I have shared the code in case of only a single state. You can use this method if you want only a single state but having multiple states for different select inputs also won't be bad as you have only 3 inputs. Having single state method would be useful if number of select inputs would have more.
import React, { useState } from 'react';
import Select from 'react-select';
function App() {
const data = [
{
value: 1,
label: 'cerulean',
},
{
value: 2,
label: 'fuchsia rose',
},
{
value: 3,
label: 'true red',
},
{
value: 4,
label: 'aqua sky',
},
{
value: 5,
label: 'tigerlily',
},
{
value: 6,
label: 'blue turquoise',
},
];
// set value for default selection
const [selectedValue, setSelectedValue] = useState([
{ value: [] },
{ value: [] },
{ value: [] },
]);
// handle onChange event of the dropdown
const handleChange = (e, no) => {
setSelectedValue(
selectedValue.map((item) => {
return selectedValue.indexOf(item) === no
? { value: Array.isArray(e) ? e.map((x) => x.value) : [] }
: item;
})
);
};
return (
<div className="App">
<Select
className="dropdown"
placeholder="Select Option"
value={data.filter((obj) => selectedValue[0].value.includes(obj.value))} // set selected values
options={data} // set list of the data
onChange={(event) => handleChange(event, 0)} // assign onChange function
isMulti
isClearable
/>
<br />
<Select
className="dropdown"
placeholder="Select Option"
value={data.filter((obj) => selectedValue[1].value.includes(obj.value))} // set selected values
options={data} // set list of the data
onChange={(event) => handleChange(event, 1)} // assign onChange function
isMulti
isClearable
/>
<br />
<Select
className="dropdown"
placeholder="Select Option"
value={data.filter((obj) => selectedValue[2].value.includes(obj.value))} // set selected values
options={data} // set list of the data
onChange={(event) => handleChange(event, 2)} // assign onChange function
isMulti
isClearable
/>
{selectedValue && (
<div style={{ marginTop: 20, lineHeight: '25px' }}>
<div>
<b>Selected Value: </b> {JSON.stringify(selectedValue, null, 2)}
</div>
</div>
)}
</div>
);
}
export default App;
{selectedValue && (
<div style={{ marginTop: 20, lineHeight: '25px' }}>
<div>
<b>Selected Values: </b>
<span>{
selectedValue.map(item => item.value.length !== 0 ?
<li>{data.filter(data => data.value === item.value[0])[0].label}</li> :
<li>No value selected</li>
)
}</span>
</div>
</div>
)}

Default value of Autocomplete is undefined in MUI v5

I have set the defaultValue prop in Autocomplete component of MUI v5 but the value is always undefined.
Excerpt from my code
const cars = [
{ label: "BMW", code: "Volkswagen" },
{ label: "Benz", code: "Mercedes" }
];
...
const formik = useFormik({
initialValues: {
car: ""
},
onSubmit: (values) => {}
});
...
<Autocomplete
id="autocomplete"
options={cars}
getOptionLabel={(option) => `${option.code} - ${option.label}`}
renderOption={(props, option) => (
<Box component="li" {...props}>
{option.code} - {option.label}
</Box>
)}
defaultValue={`${cars[0].code} - ${cars[0].label}`}
onChange={(e, value) => {
formik.setFieldValue("car", `${value.code} - ${value.name}`);
}}
renderInput={(params) => (
<TextField
{...params}
id="textField"
name="cars"
label="Cars"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
inputProps={{
...params.inputProps,
autoComplete: "new-password"
}}
/>
)}
/>
I created a working example using CodeSandbox. Could anyone please help?
you can just use:
defaultValue={cars[0]}
You got undefined-undefined because you have already described how the selected property should look like here:
getOptionLabel={(option) => `${option.code} - ${option.label}`}
Therefore, you should pass to default option an object where it's possible to access code and label values.
Changing defaultValue={cars[0]} will help.
Working Demo
The issue is in
getOptionLabel prop you were not checking wheather *
option?.code && option?.label
is defined or not so because of this undefined was showing. so change line 23 of your code to
getOptionLabel={(option) =>option.code && option.label ?
${option.code} - ${option.label} : ''}

React updating specific object of an array of objects

I am trying to change a specific item of an object , which is contained by an array of objects, yet I cannot seem to find my mistake:
This is my formset array which contains the objects :
const [formset,setFormset]=React.useState([
{
id: uuidv4(),
product:"",
price: 0,
quantity: 0,
productSubtotal: 0,
}
])
And this is how I am trying to change the product , for example:
const handleProduct = (e,id) => {
setFormset(
formset.map(item=>
(item.id !== id? item :
{
...item , product: e.target.value
})
)
)
}
EDIT: The return statement from the parent component:
return (
<div>
{formset.map((item)=>{
return(
<PieChartGroupFormPresenter
item={item}
key={item.id}
id={item.id}
handleProduct={handleProduct}
handleQuantity={handleQuantity}
purchaseList={purchaseList}
product={item.product}
quantity={item.quantity}/>
)
}
)
}
<button type="button" onClick={handleClick}>More</button>
</div>
)
The presenter component :
const PieChartGroupFormPresenter=({handleProduct,handleQuantity,product,quantity,item,purchaseList,id})=>{
return (
<div>
<FormControl>
<Select onChange={(id)=>handleProduct(id)} value={product}>
{Object.keys(purchaseList).map((item,index) =>
<MenuItem value={item} key={index}>{item}</MenuItem>
)}
</Select>
<TextField onChange={(id)=>handleQuantity(id)} value={quantity} />
<TextField value={item.price} disabled>{item.price}</TextField>
</FormControl>
</div>
)
}
I have tried multiple variations of this approach yet none of them seem to work. Thank you very much!
You passing event as id, should be
onChange={(event)=>handleProduct(event, id)}
Same mistake for other field
//<TextField onChange={(id)=>handleQuantity(id)} value={quantity} />
<TextField onChange={(event)=>handleQuantity(event, id)} value={quantity} />
const handleProduct = (e) => {
setFormset({...formset,product: e.target.value})
}

How to take out props data from a component in react-js?

I am working on a react.js app with react-select using which I have made one dropdown menu and on click of an item in menu I want to pass that item to a function which is later connected to redux store.How can I access data from a component that is used in react-select?
Here's my code that will give you more reference.
const Option = (props) => {
return (
<components.Option {...props} >
<div>{props.data.api}</div>
<div style={{ fontSize: 12 }}>{props.data.group}</div>
</components.Option>
);
};
The above code is my Option component which is used below to render a Select Menu.
return (
<StyledForm id="form_container">
<Grid>
<Grid.Row>
<Grid.Column width={3}>
<input
label="Client Name"
value={this.props.clientName}
onChange={this.setClientName}
/>
<Select options={this.props.clientGrantList} components={{ Option }} onChange={()=>this.addApiGrants(//how to pass data)} />
</Grid.Column>
This is my UI component where select menu is showing.
In the below Line in addApiGrants function I want to pass in select option data.How can I do it?
<Select options={this.props.clientGrantList} components={{ Option }} onChange={()=>this.addApiGrants(//how to pass data)} />
Thanks
The onChange handler function receives selected object as an argument. So, the code to handle this would be :
const options = [
{ value: "chocolate", label: "Chocolate" },
{ value: "strawberry", label: "Strawberry" },
{ value: "vanilla", label: "Vanilla" }
];
export default function App() {
return (
<div className="App">
<Select options={options} onChange={item => addApiGrants(item)} />
</div>
);
}
This is how the selected item from onChange handler looks like
{value: "strawberry", label: "Strawberry"}

How do you toggle the checked value of a radio button in react using hooks?

I have a group of radio buttons being built up from some external data, as per the examples below. They render and work as I'd expect with the exception of the aria-checked attribute. Clicking a radio button toggles the checked value, but it remains true when another has been selected.
If I click each radio button in sequence, I end up with a list of radio buttons that display aria-checked="true" which obviously isn't the best experience.
I'm not sure how to go about toggling the radio buttons checked value back to false when another has been checked.
Any help would be great!
Input:
const [isChecked, setIsChecked] = useState(false);
<Input
type={type}
id={id}
value={id}
name={name}
aria-label={label}
aria-checked={isChecked}
onChange={() => setIsChecked(!isChecked)}
/>
<Label htmlFor={id}>{label}</Label>
Usage:
<fieldset>
{someData.map(item => {
return (
<RadioButton
type="radio"
key={item.id}
id={item.id}
name={item.name}
label={item.label}
/>
);
})}
</fieldset>
You could try something like this.
const Radio = React.memo(function Radio({
item,
checked,
onChange
}) {
console.log("rendering", item.label);
return (
<label>
{item.label}
<input
type="radio"
value={item.id}
checked={checked}
onChange={onChange}
/>
</label>
);
});
const RadioList = ({ items, value, onChange }) => (
<div>
{items.map(item => (
<Radio
item={item}
key={item.id}
checked={item.id === value}
onChange={onChange}
/>
))}
</div>
);
const App = ({ items }) => {
const [value, setValue] = React.useState(items[0].id);
const [v, setV] = React.useState(items[1].id);
const onChange = React.useCallback(
e => setValue(e.target.value),
[]
);
const onOther = React.useCallback(
e => setV(e.target.value),
[]
);
return (
<div>
<RadioList
items={items}
value={value}
onChange={onChange}
/>
<RadioList
items={items}
value={v}
onChange={onOther}
/>
</div>
);
};
//render app
ReactDOM.render(
<App
items={[
{ id: "1", label: "one" },
{ id: "2", label: "two" },
{ id: "3", label: "three" },
{ id: "4", label: "four" }
]}
/>,
document.getElementById("root")
);
<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="root"></div>
There are two things you should change here.
When you are rendering a list of radio buttons under the same group, then the name attribute should be same for all the radio buttons. So instead of reading the name attribute from the someData, pass the same name attribute to each button. Or keep the same name in someData for each object.
After that, I don't think the state should be on input component because once you checked the radio, you are never changing its value even after clicking on some radio button. You can try it keeping the same name attribute on each Radio button.
So the solution can be to actually pass the checked attribute to the Input component depending upon which radio is actually selected. Please check the following code:
const RadioButton = ({ type, id, name, label, checked, onChange }) => {
return (
<>
<input
type={type}
id={id}
value={id}
name={name}
aria-label={label}
aria-checked={checked}
checked={checked}
onChange={onChange}
/>
<label htmlFor={id}>{label}</label>
</>
)
}
const RadioGroup = () => {
const someData = [{
id: 1,
name: 'name',
label: 'name 1'
}, {
id: 2,
name: 'name',
label: 'name 2'
}, {
id: 3,
name: 'name',
label: 'name 3'
}];
const [checkedValue, setIsChecked] = useState(1);
return (
<fieldset>
{someData.map(item => {
return (
<RadioButton
type="radio"
key={item.id}
id={item.id}
name="radioGroup"
label={item.label}
checked={checkedValue === item.id}
onChange={() => setIsChecked(item.id)}
/>
);
})}
</fieldset>
)
}

Categories

Resources