I am trying to type and save data from a input field in a Modal. For some reason I cant type inside the field once I render the modal.
This is my code:
constructor(props){
super(props);
this.state = {
showHide : false,
email: ' '
}
}
handleChange = (e) => {
this.setState({
[e.target.email]: e.target.value
})
}
This is where I attempted to have the user input.
<FormGroup>
<label for="message-text" class="col-form-label">Email Adress:</label>
<input type="text" class="form-control" name='email' placeholder="Email"
value={this.state.email} onChange={e => this.handleChange(e)} >
</input>
</FormGroup>
Any ideas on why I cant type inside the the field? Please and thank you.
So the mistake is within your setState, you have to use e.target.name. This name property will provide a string value 'email' as set in input.
Description:
Name is an HTML attribute that is accessible from Event object being passed into the function, this name is set as 'email' in your input as you can see. And since you are not updating the state correctly, that input which is right now a controlled component (value bound to state) isn't being updated.
For more details look into ES6 computed names properties.
this.setState({
[e.target.name]: e.target.value
})
Related
I am using React with Material UI's Textfield components. Was trying to find out the best way to set the form states with the least redundancy. Like for example, I have 8 different input fields. Instead of having a seperate handler for each input, like for example handleFirstName, handleLastName, handleEmail, handleInfo, etc.
So to accomplish this, I tried to create a handleChange handler which looks like below:
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value
});
}
And on each component,
<TextField
className={classes.formInput}
name="firstName"
onChange={e => this.handleChange(e.target.value)}
required
id=""
type="text"
InputLabelProps={{
shrink: true,
}}
error={!firstName}
helperText="Name is required"
label="First Name"
variant="standard" />
<TextField
className={classes.formInput}
name="lastName"
onChange={e => this.handleChange(e.target.value)}
required
id=""
type="text"
InputLabelProps={{
shrink: true,
}}
label="Last Name"
variant="standard" />
And here is my state object
constructor(props) {
super(props);
this.state = {
firstName: '',
lastName: '',
...,
};
}
These are just two of the input fields, but there are about 6 more fields that look the same. Any idea to combat this undefined name?
The problem is that you are not passing the complete event object. You are passing only the value. That is the reason why you are getting the name as undefined.
Try changing the onChange event to below -
onChange={this.handleChange}
This way you will get the complete event object in the function's e variable.
I think you need to handle multiple input field changes in single function.It is doable. try this
handleChange = (e)=>{
{name,value} = e.target;
this.setState({
[name]=value;
});
}
finally when to pass the onChange method to fields use :
onChange = {this.handleChange}
I have got Django Rest Framework backend and I am trying to post data there via React. Fetching the data is working fine. If I tried to post data with only one input it also worked fine. But when I try add more inputs, it does not work and I dont know how to handle multiple inputs..
React Code:
class Activity2project extends React.Component {
constructor(props) {
super(props);
this.state = {
virtualProjectList:[],
activeItem:{
id:null,
project_name:'',
project_name_RnD:'',
},
this.handleSubmit = this.handleSubmit.bind(this)
this.handleChange = this.handleChange.bind(this)
this.fetchVirtualProjects = this.fetchVirtualProjects.bind(this)
}
handleChange(e){
var name = e.target.name
var value = e.target.value
this.setState({
activeItem:{
...this.state.activeItem,
project_name:e.target.value,
project_name_RnD:e.target.value,
}
})
}
render(){
<div>
<input onChange={this.handleChange} type='text' id='virtual_project' name='virtual_project_name' value={this.state.activeItem.project_name} placeholder='Project Name' ></input>
<input onChange={this.handleChange} type='text' id='virtual_project_RnD' name='virtual_project_name_RnD' value={this.state.activeItem.project_name_RnD} placeholder='Project Name RnD' ></input>
<input id='submit' type='submit' name='Add'></input>
</div>
}
With this it writes the same value into inputs and I dont now how to distinguish these two inputs.
you can give your input fields ids that matches the attributes of your state:
<input onChange={this.handleChange} type='text' id='project_name' name='virtual_project_name' value={this.state.activeItem.project_name} placeholder='Project Name' ></input>
<input onChange={this.handleChange} type='text' id='project_name_RnD' name='virtual_project_name_RnD' value={this.state.activeItem.project_name_RnD} placeholder='Project Name RnD' ></input>
and then in changeHandler:
let id = event.target.id;
// then using computed property name
activeItem: {
...this.state.activeItem,
[id]: event.target.value
}
});
You can use [] brackets to bind the value of the object key to the name of the input.
For example:
handleChange(e) {
var name = e.target.name;
var value = e.target.value;
this.setState({
activeItem: {
...this.state.activeItem,
[name]: e.target.value
},
});
}
Your current code is attempting to alter both inputs at the same time. That's the reason why you can see both inputs adding the same text, as your app can't differentiate between the targets.
The following code will allow your app to see the target, check its name, and then handleChange will set the state assuming the name matches one of the available options.
As a result, the name of the inputs should reflect the state name, like so:
<input onChange={this.handleChange} type='text' id='virtual_project' name='project_name' value={this.state.activeItem.project_name} placeholder='Project Name' ></input>
<input onChange={this.handleChange} type='text' id='virtual_project_RnD' name='project_name_RnD' value={this.state.activeItem.project_name_RnD} placeholder='Project Name RnD' ></input>
And then changing handleChange to the following should work:
handleChange = (e) => {
this.setState({ [e.target.name]: e.target.value })
}
Hope that works.
I have a React Bootstrap Form component
https://react-bootstrap.github.io/components/forms/#forms
I just need to be able to get the name/ref of the input box that the user is typing inside so I can update the state dynamically. I did this already with the standard Form using:
this.setState({
[event.target.name]: event.target.value
})
but I wanted to use React's Bootstrap form. I can already get the value of the Form input, but I can't find a way to get its reference name (like if the input box is for dealerName, I am unable to get the string 'dealerName' so I can update it dynamically instead of having to hardcode the state property name to a value to update it) so I can dynamically update the state. Without that, I would have to create multiple separate functions for all the different forms I have.
This is my sample React Bootstrap Form:
<Form>
<Form.Group controlId="formDealersAdd">
<Form.Label>userId:</Form.Label>
<Form.Control type="text" placeholder="userId" ref={this.userId} onChange={this.handleInputChange}/>
<Form.Label>dealerName:</Form.Label>
<Form.Control type="text" placeholder="dealerName" ref={this.dealerName} onChange={this.handleInputChange} />
<Form.Label>dealer id:</Form.Label>
<Form.Control type="text" placeholder={did} ref={this.did} onChange={this.handleInputChange} />
<Button variant="secondary" size="lg" onClick={this.handleDealersAddFormClick}>SUBMIT</Button>{' '}
</Form.Group>
</Form>
My constructor looks like this:
class App extends Component {
constructor(props) {
super(props);
this.userId= React.createRef();
this.dealerName = React.createRef();
this.did = React.createRef();
this.state = {
userId: '',
dealerName: '',
did: '',
};
}
}
And my handleInputChange function:
handleInputChange = (event) => {
event.preventDefault()
// manually hardcoding it like this causes issues and makes my code bad
this.setState({
userId: this.userId.current.value,
dealerName: this.dealerName.current.value,
did: this.did.current.value
})
}
I was originally handling the inputChange by simply setting the state with
this.setState({
[event.target.name]: event.target.value
})
and this worked fine for the standard Form (non-React Boostrap form) and it does return the correct value for the input that is being actively updated/being typed inside by a user, but event.target.name does not work.
Thus, as you can see above, I just manually hardcoded the values to be updated inside the state object, but this is messy and causes error when the user clicks to see a new Form on my website and the properties are null and the state tries to update so it crashes.
Is there a way to update my state properties for the inputs of the React Bootstrap form similar to how I used [event.target.name] : event.target.value for the regular Form?
To get its reference name, add values to the props name would be fine
Before:
<Form.Control type="text" placeholder="userId" ref={this.userId} onChange={this.handleInputChange}/>
After:
<Form.Control type="text" name="userId" placeholder="userId" ref={this.userId} onChange={this.handleInputChange}/>
how are you? I come here to ask for your help. I'm with React JS, I have these states that are requested to send them by post to generate a user.-
class NuevoUsuario extends Component{
constructor(props){
super(props)
this.state = {
usuario: '',
password: '',
persona: {
apellido:'',
apellidoCasada:'',
nombre:'',
dni:'',
telefono:'',
celular:'',
email:'',
ubicacion: {
direccion:'',
ciudad:'',
provincia:'',
codigoPostal:'',
paisId: 0,
}
}
}
this.handleInput = this.handleInput.bind(this);
}
handleInput(e){
this.setState({[e.target.name]: e.target.value })
console.log(this.state);
}
Now what I want is that from
<div className="form-group">
<label htmlFor="exampleInput">Apellido</label>
<input
className="form-control input-lg"
type="text"
name="apellido"
onChange={this.handleInput}
/>
</div>
when doing that, the username and password are assigned, but the last name and all the others are not assigned to person.lastname or person.name, a new state is added as well, and those of person are empty {}
What I want is to be kept in person.surname. If you can help me I will be very grateful
Your input tag has attribute name that you use to select which property in state to update
<input
className="form-control input-lg"
type="text"
name="apellido"
onChange={this.handleInput}
/>
And handleInput use e.target.name to specify which property to update
handleInput(e){
this.setState({[e.target.name]: e.target.value })
console.log(this.state);
}
e.target.name will be equal to apellido, so this.state.apellido will be equal to input value.
Setting name=persona.apellido will not solve you task. You'll not be able to access this.state.persona.apellido.
The easiest solutuion I see is to make state one plane object without nested obects. Like so
this.state = {
usuario: '',
password: '',
apellido:'',
apellidoCasada:'',
nombre:'',
dni:'',
// And so on
}
Another solution is to parse this.target.name in handleInput like so (not tested!)
handleInput(e){
let name = e.target.name.split('.');
switch (name.length)
case 1:
this.setState({[e.target.name]: e.target.value });
break;
case 2:
this.setState({[name[0]]: {...this.state[name[0]], [name[1]]: e.target.value }});
break;
case 3:
this.setState({[name[0]]: {...this.state[name[0]], [name[1]]: { ...this.state[name[0]][name[1]], [name[2]]: e.target.value }}});
break;
default:;
}
console.log(this.state);
}
But I not reccomend second solution as it overcomplicated and harder to maintain in future.
First of all, in React, you need a 2-way binding between your state and input fields. You do that by adding a value prop to your input like below:
<input
className="form-control input-lg"
type="text"
name="apellido"
value={ this.state.persona.apellido } <----- Two Way
onChange={this.handlePersonaInput} <----- Binding
/>
Second, your username and password fields work because your handleInput method can only find their values in the state's first level of depth. Your Persona variables are in the second level of the state depth, and your address info is in the third level of depth. In order to reach Persona values, you need to setup a second input handler:
handlePersonaInput(e){
this.setState({persona[e.target.name]: e.target.value })
}
and your persona address fields will have third input handler:
handleAddressInput(e){
this.setState({persona.ubicacion[e.target.name]: e.target.value })
}
If you're not satisfied with 3 input handlers in your component, you can merge them into one like below:
handleInput(e){
const { name, value } = e.target;
if (name === 'usuario' || name === 'password')
this.setState({[name]: value });
else if (name === 'apellido' || name === 'apellidoCasada' || etc..)
this.setState({persona[name]: value });
else if (name === 'direccion' || etc..)
this.setState({persona.ubicacion[name]: value });
}
Just remember to think about your state structure when you want to modify one of its variables.
I'd like my controlled input to initialize with no value in the box.
The input is a number, so I don't pass in an empty ''.
Using defaultProps, I initialize the input with a null.
When typing into the input the console reports this message:
<MyInput> is changing an uncontrolled input of type number to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa).
To prevent this normally I initialize with an empty string to prevent this "switching" from happening. But with a number (I don't want to show a 0, I want nothing to show) I am not sure how to do it.
static defaultProps = {
estimatedHours: null,
estimatedMinutes: null,
}
defalut values ^^
<input
type="number"
onChange={(e) => this.handleChange('Hours', e.target.value)}
onKeyDown={this.handleKeyDown}
onPaste={this.handlePaste}
value={estimatedHours}
placeholder={hoursText}
className="slds-input th-trailmix-textbox th-time-component__input"
/>
Simpler approach is to have a fallback value be an empty string.
Works for type=number as well.
<input type="number" value={estimatedHours || ''} />
You can set value Undefined,
Also add a check for input type if required
class Input extends React.Component {
constructor(props) {
super(props);
this.state = {value: undefined};
this.handleChange = this.handleChange.bind(this);
}
handleChange = (event) => {
const isnum = /^\d+$/.test(event.target.value);
if (isnum) {
return this.setState({
value: Number(event.target.value),
});
}
};
render() {
return (
<input
type="number"
onChange={this.handleChange}
value={String(this.state.value)}
placeholder={"Please enter number"}
/>
);
}
}
and convert String to Number and vice versa
This won't throw you an error for uncontrolled input
I'd like my controlled input to initialize with no value in the box.
my problem is that I want a controlled number input with a null /
undefined initial value.
I suggest defaulting the value props in the input element with an empty string like the following:
<input
type="number"
// ...
value={estimatedHours === undefined ? '' : estimatedHours}
/>
This will make the input empty and prevent the warning from React. It'll also conveniently work well with the required prop too so the user must enter an input.
In TypeScript 3.7+, it can be shorted to the following using the nullish coalescing operator:
<input
type="number"
// ...
value={estimatedHours ?? ''}
/>
Uncontrolled inputs are simply inputs where you aren't tying value to JavaScript. So if you are rendering:
<input value={any} />
That is a controlled input.
If you want to render an uncontrolled input with an empty value you could simply write
<input type="number" /> or <input type="number" placeholder="" />
or <input type="number" placeholder="please enter a number..." />
Next, if you want to pull the value use a ref.
state = {
query: ''
}
handleSubmit = (e) => {
e.preventDefault()
this.setState({ query: this.search.value })
}
render() {
return (
<form>
<input
type="number"
ref={input => this.search = input}
placeholder=""
/>
<button type="submit" onClick={this.handleSubmit}>Submit</button>
</form>
)
}
Additionally, you can still perform logic on the return value if you need to. ie:
handleSubmit = (e) => {
e.preventDefault()
this.setState({ query: this.search.value.toExponential(2) })
// square whatever the user inputs and store in this.state.query
}
The easiest way to get the behaviour you are looking for is to define the prop type for this field to a string. This will allow '' to be used as a default prop. On form submission, you will need to make sure that the value of this field is parsed to a number.
type FormProps = {
estimatedHours: string;
estimatedMinutes: string;
}
FormProps.defaultProps = {
estimatedHours: '',
estimatedMinutes: '',
}