I want to reset state's variable to initial only for specific value
I have tried this:
const initialState={
name:'',
location:'',
....
....
....
}
this.state={
...initialState,
spinner:false,
open:false,
errorMessage:''
}
resetToInitialState = () =>{
this.setState(...initialState);
}
I am calling this resetToInitialState inside a function like this.resetToInitialState();
<TextField
id="outlined-name"
label="Machine id"
className={classes.textField}
InputProps={{
classes: {
input: classes.text,
},
}}
value={ !name && null } //tried this not working
onChange={e => this.setState({name: e.target.value})}
margin="normal"
variant="outlined"
/>
You forgot {}
this.setState({...initialState})
When you try to reset state, you need to clone initial state. If you pass in a reference to initialState, that will get mutated when you change state.
this.setState({...initialState});
To create a controlled component, TextField needs the value to be this.state.name.
<TextField
id="outlined-name"
label="Machine id"
className={classes.textField}
InputProps={{
classes: {
input: classes.text,
},
}}
value={ this.state.name }
onChange={e => this.setState({name: e.target.value})}
margin="normal"
variant="outlined"
/>
Edit: Reset TextField component when value is My Value
If you only want to reset the state when name is a specific value, you need to create a different onChange function and set onChangeReset to the onChange prop in the TextField component.
onChangeReset = e => {
if(e.target.value === 'My Value') {
this.resetToInitialState();
else {
this.setState({ name: e.target.value});
}
}
<TextField
onChange={this.onChangeReset}
value={this.state.name}
/>
Edit: Add multiple TextField components with reset function to reset all of the TextField components at the same time.
import React, { Component } from 'react';
class MyGroupedTextFields implemements Component {
constructor(props) {
super(props);
this.state = {
fields: {},
spinner: false,
open: false,
errorMessage: ''
};
}
resetTextFields = () => {
const state = { ...this.state };
state.fields = {};
this.setState({ state });
}
onTextFieldChange = event => {
const fields = {...this.state.fields};
fields[event.target.name] = event.target.value;
this.setState({ fields });
}
submit = async () => {
// perform submit network request
// pseudo code
const response = await submitForm(this.state.fields);
}
render() {
return (
<div>
<TextField
name='textField1'
onChange={this.onTextFieldChange}
value={this.state.fields.textField1}
/>
<TextField
name='textField2'
onChange={this.onTextFieldChange}
value={this.state.fields.textField2}
/>
<TextField
name='textField3'
onChange={this.onTextFieldChange}
value={this.state.fields.textField3}
/>
<button onClick={this.resetTextFields}>
Reset
</button>
<button onClick={this.submit}>
Submit
</button
</div>
);
}
}
Related
I'm currently working on a form (Material-UI) that users fill in to log a set they did for an exercise. Upon submission, it will run a GraphQL mutation. As I also have login and register functionalities that share similarities, I created a form hook for these. The login and register do not need to be reset, as this is done by redirecting them to the home page. However, for the logging set functionality, I want the modal (where the form is) to close after resetting the form back to it's initial state, so that when they choose to log another set, the form does not contain the values from the previous logged set.
Form
const initialState = {
exerciseName: "",
weight: undefined,
reps: undefined,
notes: "",
};
function MyModal() {
const [errors, setErrors] = useState({});
const { onChange, onSubmit, values } = useForm(registerSet, initialState);
const [addSet] = useMutation(ADD_SET, {
update() {
// need to reset form to initial state here
handleClose();
},
onError(err) {
setErrors(err.graphQLErrors[0].extensions.exception.errors);
},
variables: values,
});
function registerSet() {
addSet();
}
return (
<form
onSubmit={onSubmit}
id="addSetForm"
noValidate
autoComplete="off"
>
<TextField
name="exerciseName"
label="Exercise Name"
select
value={values.exerciseName}
error={errors.exerciseName ? true : false}
onChange={onChange}
>
<MenuItem key="Bench Press" value="Bench Press">
Bench Press
</MenuItem>
<MenuItem key="Deadlift" value="Deadlift">
Deadlift
</MenuItem>
<MenuItem key="Squat" value="Squat">
Squat
</MenuItem>
</TextField>
<Grid container spacing={1}>
<Grid item xs={6}>
<TextField
name="weight"
label="Weight"
type="number"
value={values.weight}
error={errors.weight ? true : false}
onChange={onChange}
/>
</Grid>
<Grid item xs={6}>
<TextField
name="reps"
label="Reps"
type="number"
value={values.reps}
error={errors.reps ? true : false}
onChange={onChange}
/>
</Grid>
</Grid>
<TextField
name="notes"
label="Notes (Optional)"
type="text"
multiline={true}
rows="4"
value={values.notes}
onChange={onChange}
/>
</form>
)
}
useForm Hook
export const useForm = (callback, initialState = {}) => {
const [values, setValues] = useState(initialState);
const onChange = (event) => {
setValues({
...values,
[event.target.name]:
event.target.type === "number"
? parseInt(event.target.value)
: event.target.value,
});
};
const onSubmit = (event) => {
event.preventDefault();
callback();
};
return {
onChange,
onSubmit,
passwordVisibility,
confirmPasswordVisibility,
values,
};
};
I'm not sure how I can access setValues from the useForm hook in the update() handler for useMutation to reset the form back to it's initial state.
Step 1: create a resetValues() function inside your useForm hook and export it
const resetValues = () => {
setValues(initialState)
};
return {
// ... OTHER EXPORTS
resetValues,
};
Step 2: Then use this function inside your component
const { onChange, onSubmit, resetValues, values } = useForm(registerSet, initialState);
const [addSet] = useMutation(ADD_SET, {
update() {
resetValues(); // SEE HERE
handleClose();
},
});
not able to get the values to change with the spread operator in handleChange()
following is the error I get The specified value "" cannot be parsed, or is out of range.
class DashboardPersonalInfoItm extends Component {
constructor(props) {
super(props);
this.state = {
personalInfo: [],
};
}
async componentDidMount() {
let data = await ApiCalls.getPersonalInfo();
this.setState({personalInfo: data});
}
following is where i am using spread operator and using to update the existing value of each field
handlePersonalInfoChange = event => {
this.setState({
...this.state.personalInfo,
[event.target.name]: event.target.value
});
};
return (
<form className={classes.container} autoComplete="off">
</div>
<TextField
id="standard-required"
disabled = {this.state.isDisabled}
label="First Name"
defaultValue="First Name"
value = {this.state.personalInfo.firstName}
className={classes.textField}
margin="normal"
onChange={this.handlePersonalInfoChange}
name="firstName"
/>
<TextField
id="standard-required"
disabled = {this.state.isDisabled}
label="Last Name"
defaultValue="Last Name"
value = {this.state.personalInfo.lastName}
className={classes.textField}
margin="normal"
onChange={this.handlePersonalInfoChange}
name="lastName"
/>
</div>
</form>
}
If you want to append it to the state then the right way to do it is.
this.setState(prevState => ({
personalInfo: prevState.personalInfo,
[event.target.name]: event.target.value
}));
You're trying to update the state root level, Please try this. One concern you initial state object is an array but you're treating it like an object.
this.setState({
personalInfo: {
...this.state.personalInfo,
[event.target.name]: event.target.value
},
});
If execute the code below and enter only date, the rendering process will run and the date input will clear.
This TextField is intended to be used as a search condition for this component.
import * as React from 'react'
import { TextField } from '#material-ui/core';
export const App = () => {
const [loading, setLoading] = React.useState(false)
const [date, setDate] = React.useState()
React.useEffect(() => {
const handle = setTimeout(() => {
setLoading(true);
// do something fetch.
setLoading(false);
}, 1000);
return () => clearTimeout(handle);
}, [loading]);
return (
<div>
<TextField type='datetime-local' onChange={e => setDate(e.target.value)} defaultValue={date} />
</div>
)
}
Input was kept when changing render to the following.
<input type='datetime-local' onChange={e => setDate(e.target.value)} />
Is there a way to keep the date entered using material-ui?
Thank you!
You have to set the initial value to TextField component and it should have a value prop like below:
<TextField
type="datetime-local"
InputLabelProps={{
shrink: true
}}
value={date}
onChange={(e) => { setDate(e.target.value) } }
/>
If you're wondering why we need to have this , look at the below example:
class SampleApp extends Component {
state = {
date : "" // setting initial state date as ""
}
render() {
return <TextField
type="datetime-local"
InputLabelProps={{
shrink: true
}}
value={this.state.date}
onChange={(e) => { this.setState({date : e.target.value}) } }
/>
}
}
In class components, We set initialValue of date state is "".
So In your functional component you have to do like below:
const App2 = () => {
//if you need to set initialvalues to muliple do this
const initialVal = {
date: '',
dateField2: ''
}
const [{date, dateField2}, setDate] = React.useState(initialVal); // need to set here // setting initial state date as ""
return <TextField
type="datetime-local"
InputLabelProps={{
shrink: true
}}
value={date}
onChange={(e) => { setDate(e.target.value) } }
/>
}
Live demo, Hope it helps
In my React App, I am able to set the state and update the database for all values except the date input field. My code is below:
import React, { Component } from 'react'
...
...
import DateInput from '../others/input/datePicker'
...
..
change = (what, e) => this.setState({ [what]: e.target.value })
changeDOB() {
this.setState({ age: document.getElementByClassNames("datePicker").value })
}
render() {
let {
...
...
age,
...
} = this.state
...
...
//date of birth
let stringAge = age.toString()
stringAge =
stringAge.substring(0, 4) +
'-' +
stringAge.substring(4, 6) +
'-' +
stringAge.substring(6, 8)
...
<DateInput
type="date"
change={this.changeDOB}
placeholder={stringAge}
className="datePicker"
/>
...
...
const mapStateToProps = store => ({
ud: store.User.user_details,
tags: store.User.tags,
session: store.User.session,
})
export default connect(mapStateToProps)(EditProfile)
export { EditProfile as PureEditProfile }
Here is DateInput code:
import React from 'react'
import { string, func, oneOf, bool } from 'prop-types'
const DateInput = ({ type, placeholder, ...props }) => (
<input
type={type}
placeholder={placeholder}
spellCheck="false"
autoComplete="false"
{...props}
/>
)
DateInput.defaultProps = {
type: 'date',
placeholder: '',
disabled: false,
}
DateInput.propTypes = {
type: oneOf(['date']),
placeholder: string.isRequired,
maxLength: string,
disabled: bool,
}
export default DateInput
I tried this.change like other fields but that does not work either.
How to get the new value updated in the state ?
Note: The text is red is the value currently in the database.
You need to add onChange attribute for the input field in the DateInput component as
const DateInput = ({ type, placeholder, ...props }) => (
<input
type={type}
placeholder={placeholder}
spellCheck="false"
autoComplete="false"
onChange = {props.Onchange}
{...props}
/>
)
Then your main component should be as
changeDOB(e) {
this.setState({ age: e.target.value });
}
render() {
return(
<DateInput
type="date"
Onchange={this.changeDOB}
placeholder={stringAge}
className="datePicker"
/>
)
}
Please find a working example here
You are passing all the props to input component but you need to pass your event handler function to onchange input element or Try onkeypress instead. Something like below. You can also try getting input value with event instead of document
Arrow function: No need of manual binding
changeDOB = (event) => {
this.setState({ age: event.target.value
})
}
<DateInput
type="date"
change={this.changeDOB}
placeholder={stringAge}
className="datePicker"
value={this.state.age}
/>
<input
type={type}
placeholder={placeholder}
spellCheck="false"
autoComplete="false"
onchange={(event) => props.change(event)}
value={props.value}
{...props}
/>
Normal function: Binding required and only in constructor
this.changeDOB = this.changeDOB.bind(this);
changeDOB(event){
this.setState({ age: event.target.value
})
}
<DateInput
type="date"
change={this.changeDOB}
placeholder={stringAge}
className="datePicker"
value={this.state.age}
/>
<input
type={type}
placeholder={placeholder}
spellCheck="false"
autoComplete="false"
onchange={props.change}
value={props.value}
{...props}
/>
The date is being taken in the ISO format whereas the display expects it in the localformat.
This worked for me:
const [deadline, setDeadline] = useState(new Date());
<input
type="date"
id="start"
name="trip-start"
value={deadline.toLocaleDateString}
onChange={(event) => setDeadline({deadline:event.target.value})}
min="2022-01-01"
max="2022-12-31"
>
</input>
I have a selectField and I want to set a value on it. Let say I type on it and when I click a button, the button will call a function that will reset the value of the textfield?
<TextField hintText="Enter Name" floatingLabelText="Client Name" autoWidth={1} ref='name'/>
You can do it in this way
export default class MyCustomeField extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 'Enter text',
};
}
handleChange = (event) => {
this.setState({
value: event.target.value,
});
};
handleClick = () => {
this.setState({
value:'',
});
};
render() {
return (
<div>
<TextField
value={this.state.value}
onChange={this.handleChange}
/>
<button onClick={this.handleClick}>Reset Text</button>
</div>
);
}
}
It's maintained that the right way is to have the component be controlled in a scenario like the accepted answer there, but you can also control the value in this gross and culturally unacceptable way.
<TextField ref='name'/>
this.refs.name.getInputNode().value = 'some value, hooray'
and you can of course retrieve the value like so
this.refs.name.getValue()
Instead of using ref you should use inputRef
const MyComponent = () => {
let input;
return (
<form
onSubmit={e => {
e.preventDefault();
console.log(input.value);
}}>
<TextField
hintText="Enter Name"
floatingLabelText="Client Name"
autoWidth={1}
inputRef={node => {
input = node;
}}/>
</form>
)
};
Here is a short simple React Hook version of the answer
export default function MyCustomeField({
initialValue= '',
placeholder= 'Enter your text...'
}) {
const [value, setValue] = React.useState(initialValue)
return (
<div>
<TextField
placeholder={placeholder}
value={value}
onChange={e => setValue(e.target.value)}
/>
<button onClick={() => setValue(initialValue)}>Reset Text</button>
</div>
);
}
I would suggest to do a little wrap on the original MUI TextField.
export default function ValueTextField(props) {
const [value, setValue] = useState(props.value);
return (
<TextField {...props} onChange={(event) => setValue(event.target.value)} value={value}/>
);
}
Now you can use your own ValueTextField component now.
<ValueTextField value={"hello world"}></ValueTextField>
I prefer this way to assign the state variables:
<TextField value={mobileNumber}
onChange={e => { this.setState({ mobileNumber: e.target.value }) }}
className={classes.root}
fullWidth={true}
label={t('mobile number')} />