i've a MaterialUI Select code, and i'm handling the value parameter dynamically. My problem is, when i set any value, it says always it's out of range, even showing the value in the valid values.
SelectInput.js:291 Material-UI: you have provided an out-of-range value `100001,250000` for the select (name="followers") component.
Consider providing a value that matches one of the available options or ''.
The available values are `0,50000`, `50001,100000`, `100001,250000`, `250001,500000`, `500001,750000`, `750001,9007199254740991`.
(anonymous) # SelectInput.js:291
And this is my code simplified:
const followers = [
{ '0-50k': [0, 50000] },
{ '50k-100k': [50001, 100000] },
{ '100k-250k': [100001, 250000] },
{ '250k-500k': [250001, 500000] },
{ '500k-750k': [500001, 750000] },
{ '+1M': [750001, Number.MAX_SAFE_INTEGER] },
];
<div className={classes.formGroup}>
<InputLabel id="followersL">Followers</InputLabel>
<Select
className={classes.field}
fullWidth
id="followers"
labelId="followersL"
margin="dense"
displayEmpty
name="followers"
onChange={(event) => setValue(event.target.value)} //I've updated the sate with the new value
value={
filters.basicInfo.followers
? value
: ''
}
variant="outlined"
>
{followers.map((element) => (
<MenuItem
value={element[Object.keys(element)]}
key={Object.keys(element)[0]}
>
{Object.keys(element)[0]}
</MenuItem>
))}
</Select>
</div>
As you can see in the message, the value selected 100001,250000 it's inside the range examples 100001,250000
Where is the problem?
add this defaultValue = "" like this
<Select
...
defaultValue=""
>
This advice may be useful for others:
If the value for Select element is object, it should be the exact instance of the object from the list of Options.
For example:
const [test, setTest] = useState("");
//list of options for Material UI select
const testOptions = [
{name: "123"},
{name: "456"},
{name: "769"},
];
//let's try to change value to {name: "123"} using JS
setTest(testOptions[0]); // everything is OK
setTest({name: "123"}); // Error! You provided out of range value!
Stringifying your value will get this to work.
element[Object.keys(element)] + ""}
If you needed it to be in its original array format before sending the result to your server you could use a function like this to do this
const strToArr = str => str.split(',').map(item => Number(item))
In my code here I have used your provided example and been able to replicate your error. But Stringifying the value removes the error and gets it to work as expected.
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 Select from "#material-ui/core/Select";
const useStyles = makeStyles(theme => ({
formControl: {
margin: theme.spacing(1),
minWidth: 120
},
selectEmpty: {
marginTop: theme.spacing(2)
}
}));
export default function SimpleSelect() {
const classes = useStyles();
const followers = [
{ "0-50k": [0, 50000] },
{ "50k-100k": [50001, 100000] },
{ "100k-250k": [100001, 250000] },
{ "250k-500k": [250001, 500000] },
{ "500k-750k": [500001, 750000] },
{ "+1M": [750001, Number.MAX_SAFE_INTEGER] }
];
const [value, setValue] = React.useState("");
const handleChange = event => setValue(event.target.value);
return (
<div>
<p>value - {value}</p>
<div className={classes.formGroup}>
<InputLabel id="followersL">Followers</InputLabel>
<Select
className={classes.field}
fullWidth
id="followers"
labelId="followersL"
margin="dense"
displayEmpty
name="followers"
onChange={handleChange}
value={value}
variant="outlined"
>
{followers.map(element => (
<MenuItem
value={element[Object.keys(element)] + ""}
key={Object.keys(element)[0]}
>
{Object.keys(element)[0]}
</MenuItem>
))}
</Select>
</div>
</div>
);
}
I ran into the same problem (you have provided an out-of-range value) when using a number state with a default value of -1:
const [selectedAccountId, setSelectedAccountId] = useState<number>(-1);
The solution to this problem was to assign an empty string for the value property in Material's UI Select component instead of using the default value of -1:
value={selectedAccountId === -1 ? '' : selectedAccountId}
Full component example:
<FormControl fullWidth>
<InputLabel>Account</InputLabel>
<Select
id="account"
value={selectedAccountId === -1 ? '' : selectedAccountId}
onChange={event => {
setSelectedAccountId(Number(event.target.value));
}}>
{allAccounts.map((account, index) => (
<MenuItem key={index} value={account.id}>
{account.exchange} ({account.id})
</MenuItem>
))}
</Select>
</FormControl>
From some research, what I've come to understand to be the reason for this warning, in my case, is the MUI Select was trying to map over a list of options that were not available on the first render as the list was coming from Axios response.
I made a component named Dropdown that renders the MUI Select component. I was providing it four props:
options: the list of options,
initialValue: the default value as I
had different default values for different instances of the Dropdown component that were not the first item of the
options list always
... and 2 other props that are not scoped for this discussion.
So, for each instance of the Dropdown component, I had to check whether the options list has any data, and only then render it. And this is what removed the warning from the console. To give a glimpse of what I did:
{viewsData.length > 0 && (
<Dropdown
options={viewsData}
initialValue={7}
{...otherProps}
/>
)}
This was bugging me for a long time. Hopefully this will help someone.
I got the same error and I solved it by making sure that the default value and the other select values thereafter are the same, for example if the default value is a string like '' then the other values are objects it will show the warning so to avoid such a problem make the default value to be either a [] or {} or most preferably null
To add to #Ait Friha Zaid response.
I also added the defaultValue attribute but also added an additional option:
const values = ['option 1', 'option 2', 'option 3'];
<FormControl fullWidth>
<InputLabel>{title}</InputLabel>
<Select
defaultValue="choose"
label={title}
onChange={e => func({...state, [keyName]: e.target.value}) }
>
<MenuItem disabled value="choose">Choose Option</MenuItem>
{values.map((value) => (
<MenuItem value={value} key={value}>{value}</MenuItem>
))}
</Select>
</FormControl>
That way you always have a disabled option that works as a placeholder which is the default option, and in case you want to do form validation, until the user changes the option, the state wont be changed.
Related
Issue summary
I get different errors at different times. When I select a suggested option, I get the following error and warning:
Material-UI: The getOptionLabel method of Autocomplete returned undefined instead of a string for 0
Material-UI: The value provided to Autocomplete is invalid. None of the options match with 0
Plus, the option doesn't get selected and the input becomes undefined. However, when trying to choose a value a second time, it gets selected (but still shows the errors).
When I clear the input I get this error:
A component is changing the controlled value state of Autocomplete to be uncontrolled.
Elements should not switch from uncontrolled to controlled (or vice versa).
Decide between using a controlled or uncontrolled Autocomplete element for the lifetime of the component.
The nature of the state is determined during the first render, it's considered controlled if the value is not `undefined`.
Code for the autocomplete component
const AutocompleteUnit = ({control, label, name, ...rest}) => {
return (
<>
<Controller
onChange={([,data]) => data}
name={name}
as={
<Autocomplete
{...rest}
autoHighlight
style={{marginTop: "25px"}}
getOptionLabel={option => option.label}
renderInput={params => (
<TextField
{...params}
label={label}
variant="outlined"
/>
)}
/>
}
control={control}
defaultValue={rest.options[0]}
/>
</>
}
Options
const districtOptions = [
{ value: "ciutatvella", label: "Ciutat Vella" },
{ value: "gracia", label: "Grà cia" },
{ value: "eixample", label: "L'Eixample" },
{ value: "sarria", label: "Sarrià " }
];
Any idea on what's wrong?
just in case some stumbles upon this: you have to use defaultValue of Autocomplete instead of the Controller
Hey just use this package below:
https://www.npmjs.com/package/mui-react-hook-form-plus
import { HookAutoComplete, useHookForm } from 'mui-react-hook-form-plus ';
const Component = () => {
const {registerState, handleSubmit} = useHookForm({
defaultValues: { movie: '' },
});
const onSubmit = (data: typeof defaultValues) => {
// will run if it is valid
}
return (
<form onSubmit={handleSubmit(onSubmit)}>
<HookAutoComplete
{...registerState('movie')}
autocompleteProps={{
options: ['Fight Club', 'Top Gun', 'Titanic']
}}
textFieldProps={{
label: 'Movie',
placeholder: 'search...',
}}
/>
<button type='submit'>Submit</button>
</form>
)
}
See Demo
I have json payload that is passed as a key value pair. I need to populate the data in a TextField select which acts as a drop down. I am able to select the first or second options in the drop down if there is two or more items in the drop down. However, when there is a single item in the drop down it does not get selected even when I click on it.
This is my code below where I set my state as I am using a functional component:
const [departments, setDepartments] = useState([]);
const [selected, setSelected] = useState();
This is code below that checks if the item in the TextField is clicked:
const handleChange = event => {
setSelected(event.currentTarget.id);
};
Also this is my code below that I set the TextField with the data that I receive from the API:
<TextField
fullWidth
label="Select Department"
margin="dense"
name="departments"
onChange={handleChange}
required
select
// eslint-disable-next-line react/jsx-sort-props
SelectProps={{ native: true }}
value={selected}
variant="outlined"
>
{departments.map(option => (
<option
key={option.id}
value={option.id}
>
{option.department}
</option>
))}
</TextField>
Kindly help me resolve this. So I can get to set the first item in the drop down even if it is the only item in the drop down.
you had some error on your code like you used event.currentTarget.id but you should use event.target.value.
However, when there is a single item in the drop down it is not called handleChange when you click on it, because handleChange is onChange event. If you have one item, you cannot change item as there is only one, so onChange event is not fired. Instead, you can add another item like "Please select" then you can select your single item. Please check this example:
import React, {useEffect, useState} from "react";
import TextField from "#material-ui/core/TextField";
function TextFieldDDL() {
const [selected, setSelected] = useState();
const departments=[
{id: -1, department: 'Please Select...'},
{id: 1, department: 'CSE'},
// {id: 2, department: 'BBA'},
// {id: 3, department: 'EEE'}
];
function handleChange(e){
console.log(e.target.value, 'e');
setSelected(e.target.value);
}
return (
<React.Fragment>
<TextField
fullWidth
label="Select Department"
margin="dense"
name="departments"
onChange={handleChange}
required
select
// eslint-disable-next-line react/jsx-sort-props
SelectProps={{native: true}}
value={selected}
variant="outlined"
>
{departments.map(option => (
<option
key={option.id}
value={option.id}
>
{option.department}
</option>
))}
</TextField>
</React.Fragment>
);
}
export default TextFieldDDL;
Update: Add item into the list
const departments = [{id: -1, department: 'Please Select...'}, ...response.data];
setDepartments(departments);
I have a requirement like, In parent component i'm getting data from api and pass that array of data to DataTable child component to display in tablular format. In that, I need to display a drop-down for each column and option are predefined(No need of dynamic values). I need only, when the user select the dropdown values, it should update in parent component state and populates that selected in particular drop-down component.
Here is what i tried,
Parent component for storing dropdown values ::
let [schema, setSchema] = useState([])
const handleChange = (event, index) => {
setSchema([
...schema,
{
Name: event.target.name,
Type: event.target.value
}
]);
};
DataTable component inside parent compoent to display data ::
<Container>
<DataTable
data={data}
meta_data={meta_data}
handleChange={handleChange}
schema={schema}
/>
</Container>
Here the iteration of each object from array to display dropdown once ::
{
Object.keys(filteredData[0]).map((field, index) => {
return (
<>
<TableCell align="left" key={field} className={classes.headings}>
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
<FormControl className={classes.margin}>
<NativeSelect
id="demo-customized-select-native"
input={<BootstrapInput />}
onChange={(e) => props.handleChange(e, index)}
name={field}
value={props.schema.length > 0 ? props.schema[index]['Type'] : null}
>
<option value={0}>Type</option>
<option value={`str`}>string</option>
<option value={`int`}>interger</option>
<option value={`float`}>float</option>
</NativeSelect>
</FormControl>
</div>
</TableCell>
</>
)
}
)}
I want, In the value prop of NativeSelect to populate the value of schema,
The schema should looks like
[
{
Name: 'passegner',
Type: 'str'
},
{
Name: 'Month',
Type: 'float'
},
]
When i retrieving the Type field of that array based in Index. It is giving 'Type' of undefined, But i actually working when console from outside of return in child component.
value={props.schema.length > 0 ? props.schema[index]['Type'] : null} - > this line giving me the error and wroking fine when console.log() outside return.
console.log(props.schema.length > 0 ? props.schema[0]['Type']) -> it is working
How to resolve?
Any suggestions would be great.
Above the return statement put a console like
console.log(props.schema[index]['Type'])
Try to figure out what went wrong, From my Guess Object.keys(filteredData[0]) may have move array values compared to props.schema[index]. So It may throw an error.
The useState hook has the following form:
const [state, setState] = useState(initialState);
In the React docs it is written:
If the new state is computed using the previous state, you can pass a function to setState. The function will receive the previous value, and return an updated value.
Meaning that you should change this:
setSchema([
...schema,
{
Name: event.target.name,
Type: event.target.value
}
]);
into this:
setSchema((prevSchema) => {
return [
...prevSchema,
{
Name: event.target.name,
Type: event.target.value
}
])
};
I am using Material UI Autocomplete for my project. As shown in official documentation, my options are,
let options = [
{ id: "507f191e810c19729de860ea", label: "London" },
{ id: "u07f1u1e810c19729de560ty", label: "Singapore" },
{ id: "lo7f19re510c19729de8r090", label: "Dhaka" },
]
Then, I am using Autocomplete as,
import React, { Component, Fragment, useState } from "react"
import TextField from '#material-ui/core/TextField';
import Autocomplete from '#material-ui/lab/Autocomplete';
import options from "/options"
function SelectLocation(props){
const [ input, setInput ] = useState("");
const getInput = (event,val) => {
setInput(val);
}
return (
<Autocomplete
value={input}
options={options}
renderOption={option => <Fragment>{option.label}</Fragment>}}
getOptionLabel={option => option.label}
renderInput={params => {
return (
<TextField
{...params}
label={props.label}
variant="outlined"
fullWidth
/>
)
}}
onInputChange={getInput}
/>
)
}
Now my UI (options list) is showing what I expected. The problem is, I am getting London or Singapore as a value of my input, but I want to get the selected object or ID from this input.
I've followed their documentation thoroughly, but couldn't find a way!
onInputChange get's fired with the actual content of the input.
You might want to use the onChange event exposed by the input props, which will return the selected element. The id should then be available as val.id in your getInput callback.
I'm building a form with an auto filling text box using react-select and formik.
<Formik
initialValues={{
assignedTo: task.assignedTo,
}}
onSubmit={(values) => {
const updatedTask = { ...task, ...values };
editTask(updatedTask);
}}
render={({ handleSubmit, handleChange, values }) => (
<form>
<Select type="text" name="assignedTo" options={options} onChange={handleChange} value={{ value: task.assignedTo, label: task.assignedTo }} />
</form>
})
/>
It throws an error Cannot read property 'type' of undefined
How to fix this and handle react-select in formik?
the first parameter of React-Select's onChange is an option value while the first parameter of formik's handleChange is an event
React-Select: onChange(value, action) => void
Formik: handleChange(e: React.ChangeEvent<any>) => void
That is the reason why you received this kind of error.
Here is my approach. I hope this helps you.
import React from 'react';
import { Formik, Form, Field } from 'formik';
import Select from 'react-select';
function SelectField(FieldProps) {
return (
<Select
options={FieldProps.options}
{...FieldProps.field}
onChange={option => FieldProps.form.setFieldValue(FieldProps.field.name, option)}
/>
)
}
export default function FormikReactSelect(props) {
const options = [
{ value: '1', label: 'White' },
{ value: '2', label: 'Yellow' },
];
return (
<Formik>
{formProps => (
<Form>
<Field name='SelectColor' options={options} component={SelectField}/>
</Form>
)}
</Formik>
);
}
As already stated, onChange handler on React-Select is different from the handleChange handler on formik.
I arrived at this from the official formik.org documentation...
Notice, I don't spread the field values like so {...field} into the react-select form because that's the problem we're trying to fix. The field values contain the onChange handler from formik which we intend to remove.
Instead, I only assign the field.name to the name attribute, and then manually set the value using the setValue handler provided through the useField helpers.
This worked for me.
import { useField, Formik } from 'formik';
import Select from 'react-select';
export default function SelectInput(props) {
const [field, meta, helpers] = useField(props);
const options = [
{ value: '1', label: 'White' },
{ value: '2', label: 'Yellow' },
];
return (
<Formik>
<Select
options={options}
onChange={(option) => helpers.setValue(option?.value)}
name={field.name}
placeholder={props.placeholder}
/>
{meta.touched && meta.error ? <div>{meta.error}</div> : null}
</div>
);
}
I had the same error but found a solution
try this
onChange={e => formik.setFieldValue('language', e[0].value)}
.setFieldValue is a Formik method that needs two arguments, first is the field name which's the value you want to update, and second, is the value
e will be an array with one or multiple selected objects, in my case, there was only one so I accessed the only object using e[0] and then bind the required property from the object, which in my case was e[0].value
Here's my very simple solution:
<Select
placeholder={`Select Flavor`}
options={[
{ value: `1`, label: `Chocolate` },
{ value: `2`, label: `Strawberry` },
{ value: `3`, label: `Vanilla` },
]}
name="flavor"
onChange={(selectedOption, _) =>
setFieldValue(`flavor`, selectedOption)
}
onBlur={handleBlur}
value={values.flavor}
/>
Works perfectly.