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;
}
Related
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}
const [userInfo, setUserInfo] = useState([]);
const handleUserInfo = (id) => {
fetch(`https://602e7c2c4410730017c50b9d.mockapi.io/users/${id}`)
.then(res => res.json())
.then(data => setUserInfo(data))
}
<input type="text" defaultValue={userInfo?.profile?.firstName + userInfo?.profile?.lastName} className="form-control bg-light" id="exampleInputName" aria-describedby="name"></input>
I am expecting to see both firstname and last name in that input field with a gap between first name and last name. But I see NAN because I tried to add firstname and lastname using plus (+)
The NAN doesn't show up if I only want to see the first name when the default value is defaultValue={userInfo?.profile?.firstName}
Hello and welcome to Stack Overflow!
Input's defaultValue is set on the initial load of your component. Your request is asynchronous which means that you are probably getting the result after the initial load. So you need to transform your component into a controlled component. Meaning, you will have to create a state that will hold the input value as well as to listen on the onChange event and alter your state to reflect the changes. You can check the official docs here for more info on forms and their behavior.
export default function ExampleComponent() {
const [userInfo, setUserInfo] = React.useState([]);
const [inputValue, setInputValue] = React.useState('');
React.useEffect( () => {
handleUserInfo(5)
}, [])
const handleUserInfo = (id) => {
fetch(`https://602e7c2c4410730017c50b9d.mockapi.io/users/${id}`)
.then(res => res.json())
.then(data => {
setInputValue(`${data?.profile?.firstName} ${data?.profile?.lastName}`)
setUserInfo(data)
} )
}
return (
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
className="form-control bg-light"
id="exampleInputName"
aria-describedby="name"
/>
)
}
You have a typo when you are trying to display default value, try to change
userInfo?.profile?.firstName + userInfo?.profile?.lastlName to
userInfo?.profile?.firstName + userInfo?.profile?.lastName.
(lastName was misspelled incorrectly).
also it's a better way to use template literals
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}))
}
this is a continuation of:
How to use a handler function for two different purposes. SPFX (React/TypeScript)
which I've made a little progress from, so this isn't a duplicate, it's part 2 as it were.
My current code handler is:
const {value} = (evt.target as any);
const countKey = `${evt.target.name}Count`;
const obj = {
[evt.target.name]: value,
[countKey]: value.toString().length,
};
this.setState({
...this.state,
obj
}, () => { console.log(obj), console.log(countKey+'countKey'), console.log(value+'value');});
}
The render with the fields in question:
<td><TextField //THIS IS THE USER INPUT TEXTFIELD WHICH I WANT COUNTED BY THE TEXTFIELD BELOW!
name="EssCrit1"
value={this.state.EssCrit1}
onChange={this.handleChange}
multiline rows={2}
/>
</td>
<td ><TextField //THIS IS THE CHARACTER COUNTER FIELD!
name="EssCritChars1"
value={this.state.EssCrit1Count}
disabled={true}
/>
</td>
As you can see I'm logging obj and this is showing the correct textfield value typed in also it is counting how many characters. Problem is it doesn't allow text to be typed into the textfield. The value (EssCrit1) and the (EssCrit1Count) field seem to be registering the key press showing:
[object Object]: {EssCrit1: "h", EssCrit1Count: 1}
EssCrit1: "h"
EssCrit1Count: 1
__proto__: Object
in the console. But as mentioned it doesn't allow any text to be typed into the field. It seems as if the state is being overwritten as soon as something is typed in. Or something else which isn't apparent.
If it helps here is my state for the EssCrit1 textfield and it's accompanying character counter:
EssCrit1:null,
EssCrit1Count: null,
Went with:
public handleChange = (evt: any) => {
const {value} = (evt.target as any);
const countKey = `${evt.target.name}Count`;
const obj = {
[evt.target.name]: value,
[countKey]: value.toString().length,
};
this.setState(prevState => ({prevState, ...obj}));
}
and for the render:
<td><TextField
name="EssCrit1"
value={this.state.EssCrit1}
onChange={this.handleChange}
multiline rows={2}
/>
</td>
<td ><TextField
name="EssCrit1Count"
value={this.state.EssCrit1Count}
disabled={true}
/>
</td>
Matched up the text 'Count' at the end of the const CountKey variable assignment from the handler with the states that required it. The main issue was the updating of the states. I changed this to
this.setState(prevState => ({prevState, ...obj}));
from
this.setState(prevState => ({...prevState, newState });
which encompasses the changes detailed in the handler. Hope this helps someone. I'm going to reverse engineer what I have learnt from the magnificent help I've received. Thank you to everyone as always.
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>
)
}