I have four input fields of an html form which the name attributes are extracted using the event handler onChangeHandler. these names are extracted using e.target.name . Now here is the issue, I want to update the state object by copying an initialState object into the state object but making sure the current input experiencing the onChange event is also updated. using e.target.name to set the property name does not work, but [e.target.name] works the magic.
why is this so? why does [e.target.name] work instead of e.target.name?
here is the code
const initialState = {
displayName : '',
email : '',
password : '',
password_confirmation: ''
}
function SignUpForm(){
const [fieldState , setFieldState] = useState(initialState);
const {displayName , email , password , password_confirmation} = fieldState;
const onChangeHandler = (e) => {
console.log(e)
//updating state when it is an object
//https://beta.reactjs.org/learn/updating-objects-in-state
setFieldState({
...fieldState , //Copy the initial state
[e.target.name] : e.target.value //but update this property
})
}
return(
<form>
<input type="text" name="displayName" onChange={onChangeHandler} value={displayName}/>
<input type="email" name="email" onChange={onChangeHandler} value={email}/>
<input type="password" name="password" onChange={onChangeHandler} value={password}/>
<input type="password" name="password_confirmation" onChange={onChangeHandler} value={password_confirmation}/>
</form>
);
}
export default SignUpForm```
In General, thats the way of adding dynamic property to an object, you need to wrap the prop. name with square brackets([]).
let obj = {
name: 'ray'
};
obj['age'] = 20; // obj = {name: 'ray', age: 20};
To access object property Dot(.) operator can use.
Javascript allows you to put an expression in brackets [], that will be computed and used as the property name.
const param = "size";
const config = {
[param]: 12
};
console.log(config); // {size: 12}
Related
So the problem is when the input value is auto-filled and when I click submit button input field value is not recognized unless I change something in there for example delete and add again the last word to the first name. How can I make value recognized immediately?
// This is 'context' from where we get info about 'user' like first name, last
// name, email etc
const { user } = useContext(UserContext);
const [firstName, changeFirstName] = useState(user.firstName);
const [lastName, changeLastName] = useState(user.lastName);
/**
* #param {Object} e
*/
const handleChange = (e) => {
handleUserInputChange(e);
changeFirstName(e.firstName);
changeLastName(e.lastName);
}
<input
type="text"
value={firstName}
name="firstName"
onChange={(e) => handleChange(e)}
/>
There is something fishy with your onChange handler:
const handleChange = (e) => {
handleUserInputChange(e);
changeFirstName(e.firstName);
changeLastName(e.lastName);
}
At this point, you don't have access to the e.firstName and e.lastName values. The e object is just the event from the onChange call (find an example in the React docs here).
For the first name, you could instead use something like this:
const handleChange = (e) => {
changeFirstName(e.target.value);
}
I would recommend refactoring a little bit to make it more understandable. Anyway, you are looking to (input)="" to change the value as user types. You can't have property as a const (constant) if you play to overwrite it.
html
<input #firstName
type="text"
(value)="firstName"
name="firstName"
(input)="onFirstNameChange(firstName.value)"/>
<input #lastName
type="text"
(value)="lastName"
name="lastName"
(input)="onLastNameChange(lastName.value)"/>
ts
firstName: string;
lastName: string;
onFirstNameChange(event: any) {
this.firstName = event;
}
onLastNameChange(event: any) {
this.firstName = event;
}
I cannot modify input predefined value.
constructor(props) {
super(props);
this.state = {
userDetails: this.props.location.state.userDetails,
token: "",
firstName: "",
lastName: "",
email: "",
roles: []
};
This is the method that I use for handling input:
handleInputChange = (e) => {
const target = e.target;
const value = target.value;
const name = target.name;
this.setState = {
[name]: value,
};
};
This is the input element:
<input
type="text"
value={this.state.userDetails.firstName}
name="firstName"
ref="firstName"
onChange={this.handleInputChange}
/>
In the UI I cannot delete its(input) default value taken from the state neither type something else. If I comment the value this problem disappears.
What am I doing wrong in this case?
<input> element always reads its value from this.state.userDetails.firstName, which doesn't change.
Because of that, <input>'s value has to be firstName:
<input
type="text"
value={this.state.firstName}
...
Then you can, for instance, set firstName: this.props.location.state.userDetails.firstName as default value on first render.
I am trying to input email value from user and store it in a state variable. I have tried the following code but getting an error:
<Form.Control type="email" required placeholder="Enter email" value={this.state.email} onChange={this.setEmail}></Form.Control>
State variable is defined as follow:
this.state = {
email: '',
}
Following is my code to set the value entered by user in email:
setEmail = (e) => {
this.setState(() => ({email: e.target.value}))
}
I tried printing e.target.value. It is correct. But while running this code, I am getting error:
Cannot read property 'value' of null
Any comments on how to fix this issue?
That is happening because the event is not persisted, and it is used in an asynchronous function (setState is async).
Just extract it before calling setState.
setEmail = (e) => {
const {value} = e.target;
this.setState(() => ({email: value}))
}
Trying to log the values of name, day and dob elements stored in dataEdited as object.Two of the elements display Undefined with just one displaying the correct value.
Here is the code
/* two-way state binding */
dataChange(event){
const target = event.target;
const value = target.value; //gets value of the textbox
const name = target.name;
this.setState({ dataEdited: {[name]: value} });
}
handleUpdate(event){
event.preventDefault();
const {name,day,dob} = this.state.dataEdited;
console.log(name, day, dob);
/* this.setState({ toggle: false }) */
}
State
this.state = {
name: '',
day: '',
dob: '',
items : [],
currentItem: {},
dataEdited: {},
toggle: false,
loading: false
}
Render
<form onSubmit={this.handleUpdate}>
<input
className=""
name="name"
onChange={this.dataChange}
defaultValue={this.state.currentItem.name}
placeholder= "Celebrant's Name"
ref={name => this.name = name}
required />
<input
className=""
type="number"
name="day"
min="1"
max="31"
ref={day => this.day = day}
onChange={this.dataChange}
defaultValue={this.state.currentItem.day}
placeholder= "day" />
<input
className=""
name="dob"
type="month"
onChange={this.dataChange}
defaultValue={this.state.currentItem.dob} />
<button type="submit">update</button>
<button onClick={this.handleEditCancel}>cancel</button>
</form>
This is the result on the console
undefined undefined "2020-08"
I don't understand how this is possible, can I get an explanation. Also, how can I fix this?
When you execute this.setState({ dataEdited: {[name]: value} }); you overwrite the other values in the object assigned to dataEdited.
You should change that to this.setState({ dataEdited: { ...this.state.dataEdited, [name]: value} }); to preserve the previous values inside this.state.dataEdited
UPDATE (Thanks #JMadelaine): You should use this.setState(prev => ({ dataEdited: { ...prev.dataEdited, [name]: value}})); to ensure that no concurrent state changes affects the setState()
More info: https://stackoverflow.com/a/50837784/10201813
Problem
you are overwriting the same dataEdited variable over and over when you call this.setState({ dataEdited: {[name]: value} });
Thus only the last changed data will be present inside dataEdited
Solution
Seperately save the data or change setState function appropriately
You are overwriting the state variable dataEdited everytime you call
this.setState({ dataEdited: {[name]: value} });
so you want to change spread the object dataEdited and the state After that add or change the name,dob or day
this.setState({
...this.state,
dataEdited: { ...this.state.dataEdited, [name]: value }
});
CodeSandbox here
I am new to React and was learning how to handle multiple inputs in form. Here is the code :
class Login extends Component {
constructor () {
super();
this.state = {
email: '',
password: ''
};
this.handleChange = this.handleChange.bind(this);
}
handleChange (evt) {
// check it out: we get the evt.target.name (which will be either "email" or "password")
// and use it to target the key on our `state` object with the same name, using bracket syntax
this.setState({ [evt.target.name]: evt.target.value });
}
render () {
return (
<form>
<label>Email</label>
<input type="text" name="email" onChange={this.handleChange} />
<label>Password</label>
<input type="password" name="password" onChange={this.handleChange} />
</form>
);
}
}
The question is how can this.setState({ [evt.target.name]: evt.target.value }); replace several handlers? Does [evt.target.name] represent both inputs?
[evt.target.name] doesn't necessarily represent both inputs, it merely takes the name of the event's target and makes it the key for setState.
This means that when the email form changes, the this.setState will act as follows:
this.setState({ email: evt.target.value });
For the password this works the same;
this.setState({ password: evt.target.value });
So it doesn't necessarily replace several handlers, it mostly replaces them and supplies a shorter way to handle the event. (Think DNRY (Do Not Repeat Yourself)).
However many fields you have in the form, this.setState({ [evt.target.name]: evt.target.value }); will behave as explained above.
To further elaborate, in your current form, with a field for the email and a field for the password, the following will happen;
handleChange (evt) {
this.setState({ [evt.target.name]: evt.target.value });
}
Above function will take the event's target and extract the name and value attributes. So for EACH input with this change handler it'll change the function to i.e. the following if the email gets changed;
handleChange (evt) {
this.setState({ email: "email#domain.com" });
}
OR i.e. for the password
handleChange (evt) {
this.setState({ password: "superstrongpassword" });
}
OR i.e. for the name
handleChange (evt) {
this.setState({ name: "John Doe" });
}
Hope this helps!
This is basic example.
class Login extends Component {
constructor () {
super();
this.state = {
email: '',
password: ''
};
this.handleChange = this.handleChange.bind(this);
}
handleChange (evt, field) {
// check it out: we get the evt.target.name (which will be either "email" or "password")
// and use it to target the key on our `state` object with the same name, using bracket syntax
this.setState({ [field]: evt.target.value });
}
render () {
return (
<form>
<label>Email</label>
<input type="text" name="email" onChange={(event)=>this.handleChange(event, "email")} />
<label>Password</label>
<input type="password" name="password" onChange={(event)=>this.handleChange(event, "password")} />
</form>
);
}
}
This works because evt is a change event, evt.target is the changed DOM element and evt.target.name is the value of the name attribute of that element.
This means that when you change one of the <input> elements the handleChange function is called and the state's email or password (the names of those two inputs) property is changed to the changed element's value.
{[variable]: value} is just the syntax you use when you want to use a string as a property name in an object literal.
Every input has a name attribute which is used to reference elements in JavaScript, or to reference form data after a form is submitted. Here you are using name and password as names.
this.setState({ [evt.target.name]: evt.target.value })
This is using ES6 Computed property names.
evt.target.name takes the name of the input (i.e the evt.target) to which the handler is attached and being called and sets it as the key for your state. So, essentialy each time you change something in the input, your state corresponding to that input's name changes as well.
Keep one thing in mind. You need to keep the initial state names and the names of your input consistent with each other for this to work.
You can always write seperate handlers but that just convolutes the codebase and are essentially doing the same thing. So it is just following the DRY methodology. Might as well use this.
Hope this helps!
for create a state for this, is necessary create a object with any property and set
just behaivor on component an above class with your scheme class and component this is trigger for you response
Create an object property
state = {
nameForProperty: '',
anotherNamenameForProperty: ''
}
create an event for setState a pass event for function callback
onHandleEvent = e => {
this.setState ({
[e.target.name]: e.target.value,
})
console.log(this.setState)
};
Call function from input
<form>
<input name="namenameForProperty" onChange={this.onHandleEvent} value={this.state.} />
</form>
You can try something like this.
handleChange (evt) {
let name = evt.target.name
this.setState({ [name ]: evt.target.value });
}
Well, you can also adopt chained arrow function handleChange as handleChange = key => e => { ... } , then use it in input as onChange={this.handleChange('mail')}.
constructor(ops) {
super(ops)
this.state={
prompt: '',
form: {
name: '',
mail: '',
message: ''
}
}
}
handleChange = key => e => {
let newForm = {
...this.state.form,
[key]: e.target.value
}
this.setState({
form: newForm
})
}
render() {
let { name, mail, message } = this.state.form
return (
<form action="#">
<input type="text" value={name} onChange={this.handleChange('name')} className="form-control" placeholder="Name*" />
<input type="email" value={mail} onChange={this.handleChange('mail')} className="form-control" placeholder="E-mail*" />
<textarea value={message} onChange={this.handleChange('message')} className="form-control" placeholder="Message"></textarea>
</form>
)
}