<Select> component from material-ui not updating changes - reactjs

The dropdown looks and works fine, but will not update a new selection and I get the following error message:
Warning: Use the `defaultValue` or `value` props on <select> instead of setting `selected` on <option>.
Selected is not set on <option> as far as I'm aware, so it must be set by material-ui's component. Anyway, if I change value into defaultValue, I get the following error message:
aterial-UI: the `value` property is required when using the `Select` component with `native=false` (default).
I thought it was a problem in Material-ui itself, but their example works fine, although there are no parent/child components in the example like mine.
Example:
https://codesandbox.io/s/7yk922om7x
My code (shortened for brevity):
constructor(props) {
super(props)
this.state = {
languageValues: {
htmlFor: 'lstLanguages',
value: 'english',
input: <Input name="language" id="lstLanguages"/>,
options: [
{ value: 'dutch', text: 'Nederlands' },
{ value: 'french', text: 'Français' },
{ value: 'english', text: 'English' },
{ value: 'german', text: 'Deutsch' }],
helperText: 'Choose your language',
}
}
}
handleChange = event => {
event.preventDefault();
this.setState({ [event.target.name]: event.target.value });
}
render() {
return (
<div>
<h2 id="speechTitle">Speech Settings</h2>
<hr/>
<FormGroup column='true'>
<DropDown
dataToFill={ this.state.languageValues }
onChange={ this.handleChange.bind(this) }
/>
Dropdown.js:
const DropDown = ({dataToFill}) => {
const menuItemValueList = dataToFill.options.map((item, i) => {
return <MenuItem value={ item.value } key={ i }>{ item.text }</MenuItem> //Always provide a key
})
return (
<FormGroup column='true'>
<FormControl>
<InputLabel htmlFor={ dataToFill.htmlFor }>Languages</InputLabel>
<Select
defaultValue={ dataToFill.value }
input={ dataToFill.input }
>
{ menuItemValueList }
</Select>
<FormHelperText>{ dataToFill.helperText }</FormHelperText>
</FormControl>
</FormGroup>
);
}
EDIT 1
I think I have found the problem: The handleChange function expects [event.target.name] but the value that needs changing is nested in the state, I'm not sure how I can access it...
Event handler code:
handleChange = event => {
this.setState({ [event.target.name]: event.target.value })
}
Nested state object:
languageValues: {
htmlFor: 'lstLanguages',
value: 'english',
input: <Input name="language" id="lstLanguages"/>,
options: [
{ value: 'dutch', text: 'Nederlands' },
{ value: 'french', text: 'Français' },
{ value: 'english', text: 'english' },
{ value: 'german', text: 'German' }
],
helperText: 'Choose your language',
},

Related

React-select defaultValue is not showing

I'm using Formik and React-select library and defaultValue is not working/taking effect and it remains empty, i don't know why this is happening.
MySelectInput component:
interface Props {
// .. other props
options: CategoryOptions[];
defaultCategory: CategoryOptions;
}
const MySelectInput: React.FC<Props> = (props) => {
const [field, meta, helpers] = useField(props.name);
return (
<>
<Select
options={props.options}
isSearchable
defaultValue={props.defaultCategory}
onChange={(v) => helpers.setValue(v!.value)}
onBlur={() => helpers.setTouched(true)}
placeholder={props.placeholder}
styles={customSelectStyles}
/>
</>
)
};
export default MySelectInput;
Usage:
<MySelectInput
options={CategoryOptions}
placeholder="Category"
name="category"
label="Category"
defaultCategory={{ value: activity.category, label: activity.category }}
/>
My array of objects (CategoryOptions):
export const CategoryOptions: CategoryOptions[] = [
{ value: 'drinks', label: 'Drinks' },
{ value: 'music', label: 'Music' },
{ value: 'travel', label: 'Travel' },
];
The options are working and displaying well but defaultValue is not working. If i use static strings inside object properties like:
defaultCategory={{ value: "test", label: "test" }}
is working well. Any idea?
I think you should probably use an item from CategoryOptions.
Instead of
defaultValue={props.defaultCategory}
do
defaultValue={props.defaultCategory[0]}
I'm also wondering why your CategoryOptions object is same as the CategoryOptions type. Maybe you should rename it to categoryOptions

Generate React form fields from JSON

i am trying to generate a form from JSON config. I am parsing the JSON and using map functions to generate material UI TextField components.
But issue is that the generated components do not get rendered, instead the whole JS code appears on screen. Not sure why.
here is my code in 2 files:
FormConfig.js:
"Form1": {
"fields": [
{
uiElement: "TextField",
id: '"standard-name"',
name: "'asdada'",
className: "{classes.textField}",
value: "{this.state.name}",
onChange: '{this.handleChange("name")}',
required: true,
margin: '"normal"'
},
{
uiElement: "TextField",
id: '"standard-uncontrolled"',
name: '"asda"',
label: '"Required"',
className: '"{classes.textField}"',
value: '"asd"',
onChange: "{}",
required: true,
margin: '"normal"'
}
]
},
"OtherForm":
{
"fields": [{}, {}]
}
}
const getForm = formName => {
return FormConfig[formName].fields.map(field => `<${field.uiElement} `+
Object.keys(field).filter(k => k !== 'uiElement')
.map(k => {
return k + "=" + field[k];
})
.join(" ") + `/>`
)
}
export default getForm;
TestForm.js
class TextFields extends React.Component {
state = {
name: 'Cat in the Hat',
age: '',
multiline: 'Controlled',
currency: 'EUR',
};
handleChange = name => event => {
this.setState({ [name]: event.target.value });
};
render() {
const { classes } = this.props;
return (
<form className={classes.container} noValidate autoComplete="off">
{
getForm("Form1")
}
<TextField
required
id="standard-required"
label="Required"
defaultValue="Hello World"
className={classes.textField}
margin="normal"
/>
I was expecting that the call to getForm() would have rendered my fields, but instead it spits out this on the web page. Am I doing something wrong?
<TextField id="standard-name" name='asdada' className={classes.textField} value={this.state.name} onChange={this.handleChange("name")} required=true margin="normal"/><TextField id="standard-uncontrolled" name="asda" label="Required" className="{classes.textField}" value="asd" onChange={} required=true margin="normal"/><TextField id="standard-read-only-input" name="asd" label="Read Only" className={classes.textField} value="asd" onChange={} required=false margin="normal" InputProps={{readOnly: true}}/><TextField id="standard-dense" name="w3rg" label="Dense" className={classNames(classes.textField, classes.dense)} value="sdas" onChange={} required=false margin="dense"/>
try to return the component at mapping:
const getForm = formName => {
return FormConfig[formName].fields.map(field => evalComponent(field))
}
const evalComponent = field => {
let { uiElement, ...props } = field
switch(uiElement) {
case 'TextField':
return <TextField {...props}/>
default:
return false
}
}

React-Select: Getting multiple onChange values from dropdown

import React from 'react';
import Select from 'react-select';
const options = [
{ value: 'all', label: 'all' },
{ value: 'destroyed', label: 'Destroyed' },
{ value: 'damaged', label: 'Damaged' },
{ value: 'physicalDamage', label: 'PhysicalDamage' }
]
class SearchFilters extends React.Component {
_onChange = (e, options) => {
const onChangeData = {
value: e.value,
name: e.label,
result: options.find(item => item.value === e.value)
};
console.log(onChangeData.value);
return onChangeData;
};
render(){
return(
<div>
<Select
options={options}
onChange={e => this._onChange(e, options)}
isMulti={true}
/>
</div>
)
}
}
export default SearchFilters
From the above code if isMulti is false in select, I'm able to print the value of the selected option in console, but if I change it to true, I get the value as undefined.
I need help in fixing this. Thanks in advance.
Ouput:

Getting error on React Component on Render

As I an New to ReactJS.
What i am doing is when i type is any field State should be update in particular field -
As This is my LoginComponet and Setting small Form -
import React, { Component } from 'react';
import '../css/style.css';
export class LoginCompoent extends Component {
constructor(props) {
super(props);
this.state = {
field: {
phone: {
value: '',
validations: [],
errors: []
},
password: {
value: '',
validations: [],
errors: []
}
}
};
this.handelChangeEvent = this.handelChangeEvent.bind(this);
}
componentDidMount() {
}
handelChangeEvent(event) {
this.setState({
field: {
[event.target.id]: {
'value': event.target.value
}
}
});
}
render() {
console.log(this.state);
return (
<div className="loginMainDiv" >
<div className="">
<input className="login_inp" placeholder="Mobile Number"
value={this.state.field.phone.value}
onChange={this.handelChangeEvent}
type="text" name="phone" id="phone"
/>
<input className="login_inp" placeholder="Password"
value={this.state.field.password.value}
onChange={this.handelChangeEvent}
type="password" name="password" id="password"
/>
<button className="login_btn" >Login Safely</button>
</div>
</div>
);
}
}
Expected Result - on console.log(this.state);
when I type 9 in phone field -
field: {
phone: {
value: '9',
validations: [],
errors: []
},
password: {
value: '',
validations: [],
errors: []
}
}
Getting Result -
field: {
phone: {
value: '9'
}
}
I don't know why all fields are suddenly hidden when i update only phone field. ?
Because of this password is not setting in the form. ERROR - this.state.field.password is undefined ???
Deep merging issues, as you set a name property to your input, this should work:
this.setState(prevState => ({
field: {
...prevState.field,
[event.target.name]: {
'value': event.target.value
}
}
}));
In your handleChangeEvent function, you are updating the value of the field in the state:
this.setState({field: {
[event.target.id]: {
'value': event.target.value
}
}})
This will obviously overwrite the existing value of the field.
In your case, I would recommend using the callback function inside the setState. Please see the docs.
For example, if you want to update the value of the phone but also you want the value of the password to remain unchanged, You could do something like this:
handleChangeEvent = (event) => {
this.setState((prevState) => {
return {field: {
[event.target.id]: event.target.value,
...prevState.field
}
};
});
}
As I have tried all the Above answers but facing the error.
ERROR- Uncaught TypeError: Cannot read property 'id' of null on this.setState( prevState => ( {} ) ).
The Problem was - the reference of event are not maintain in async call that's why event.target is becoming null and getting above Error.
I got the concept of event.persist() which helps to maintain all the references of the event and make the Wrapper to the browser event with async calls.
You can go to this Article Reference

semantic ui react Setting dropdown value to state

how to have dropdowns selected value in state.here is my code iam getting value for name field but dropdown not working, can anyone find out what i am missing?
MyComponent.js
import React,{Component} from 'react';
class MyComponent extends Component{
state={
data:{
name:'',
subject:''
}
}
onChange = e =>
this.setState({
data: { ...this.state.data, [e.target.name]: e.target.value }
},()=>{
console.log(this.state.data);
}
)
render(){
const {data}=this.state;
const subjects= [
{text: '1',value: 'kannada'},
{text: '2', value: 'english'},
{text: '3',value: 'hindhi'}
]
return(
<div>
<Input
name="name"
onChange={this.onChange}
placeholder='Your name ...'
/>
<Dropdown
placeholder='Select Subject'
name="subject"
onChange={this.onChange}
selection
options={subjects}
/>
</div>
)
}
}
export default MyComponent;
how to have selected dropdown value in state?, iam getting changed value for name field but for dropdown not getting.
handleChange = (e, { value }) => this.setState({ value })
Add value prop to Dropdown
render(
const { value } = this.state;
return(
<Dropdown
placeholder='Select Subject'
name="subject"
onChange={this.handleChange}
selection
options={subjects}
value={value}
/>)
)
If anyone is using react hooks and semantic ui react, this is how I got it to work, without having to create a separate change handler function for it.
const options = [
{ key: "1", text: "Speaker", value: "SPEAKER" },
{ key: "2", text: "Event Planner", value: "EVENT_PLANNER" }
];
const [values, setValues] = useState({
firstName: "",
userType: ""
});
const onChange = (event, result) => {
const { name, value } = result || event.target;
setValues({ ...values, [name]: value });
};
<Form.Dropdown
placeholder="I am a.."
name="userType"
label="User Type"
selection
onChange={onChange}
options={options}
value={values.userType}
/>
What kept throwing me off was the 'result' that the onChange function takes as an argument. Since the options are stored as objects in an array, the correct way to access their values is with the 'result' and not 'event.target.'
One more way to use DropDown in React Semantic. it worked perfectly for me.
const options = [
{ key: 'ex1', text: 'Example 1', value: 'Example 1' },
{ key: 'ex2', text: 'Example 2', value: 'Example 2' },
]
Method to set value
handleSelectChange=(e,{value})=>this.setState({stateValue:value})
In Form
<Form.Select fluid label='List Example' options={options}
placeholder='List Example'
value={value}
onChange={this.handleSelectChange} />
You can use the Form.Field also.
For more information.
constructor(props) {
super(props);
this.state={
subject : ""
}
}
handleChange = (e, result) => {
const { name, value } = result;
this.setState({
[name]: value
});
};
render() {
const options = [
{ key: 'ex1', text: 'Example 1', value: 'Example 1' },
{ key: 'ex2', text: 'Example 2', value: 'Example 2' },
];
return(
<div>
<Form>
<Form.Field
placeholder="Subject"
name="subject"
label="Subject"
control={Dropdown}
fluid
selection
onChange={this.handleChange}
options={options}
value={this.state.subject}
/>
</Form>
</div>
);
}

Resources