Am trying to build form inputs in reactjs. the code below works for just one form inputs.
Now I want to add two more form inputs as per
Firstname <input type="text" id="fname" name="fname"><br>
Lastname <input type="text" id="lname" name="lname"><br>
below is the working code that I want to implement the two form inputs above.
source
https://reactjs.org/docs/forms.html
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
The best way I've found to manage forms in React is to make sure each of your <input> tags has a name value. Then ensure that your component's state has fields for each input that matches the name exactly.
In your onChange handler, you can then say:
handleChange(event) {
this.setState({ [event.target.name]: event.target.value });
}
This will update the state with change to any of the inputs, and apply the change to that specific state value.
Then for handleSubmit, you send those values from state to where ever you need to process the form information.
try this one
handleChange(event){
this.setState({[event.target.name]:event.target.value});
this.setState({[event.target.name]:event.target.value});
}
Related
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.
Based on the React Forms documentation, I am wondering why the following example is valid ?
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
As this.setState is asynchronous, you could have a change and a submit event that follow each other, so you would obtain the following senario : :
change event emitted
submit event emitted
handleChange is called, so this.setState is called, as it's asynchronous the state is not updated immediately
handleSubmit is called, this.state.name doesn't refer to the last value typed into the input field as the state update hasn't been applied yet.
The state is updated
So if my understanding is correct, in this example, the handleSubmit is not guaranteed to revrieve the last value typed into the input field ?
I currently have an input field set up so the inputs value will be console logged when a button is pressed, I am trying to render a component instead of this console.log.
I can get it to sorta work but it re-renders every time I type a single character because I'm not sure how to check for the click within the render method, I read through some of the docs but couldn't figure out how do to it. How could I go about achieving this?
here is the code
class Form extends React.Component {
constructor(props) {
super(props)
this.state = {
input: ''
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({input: e.target.value});
}
handleSubmit(e) {
e.preventDefault();
console.log(this.state.input)
}
render() {
//Not sure how to check for this
if (this.state.input) {
return <Fetch username={this.state.input} />
}
return(
<form>
<label>
Name:
<input type="text" value={this.state.input} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" onClick={this.handleSubmit} />
</form>
);
}
}
let me know if you need anymore information. Thanks!
Edit: By the way, I want to be able to submit the form many times, sorry, I should have been more descriptive of my problem. I want the Form component to stay rendered and I want the Fetch component to get rendered on clicked
A solution depends on your needs and there might be a lot of them. The simplest way, just to demonstrate:
class Form extends React.Component {
constructor(props) {
super(props)
this.state = {
input: '',
submitted: false, // adding the flag
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({input: e.target.value});
}
handleSubmit(e) {
e.preventDefault();
this.setState({ submitted: true }); // set the flag on submit
console.log(this.state.input)
}
render() {
//Not sure how to check for this
if (this.state.submitted) { // show the component by the flag
return <Fetch username={this.state.input} />
}
return(
<form>
<label>
Name:
<input type="text" value={this.state.input} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" onClick={this.handleSubmit} />
</form>
);
}
}
Obviously, in real application it's too simple logic. You have to define first, what are you trying to reach.
UPDATE:
If you want to keep the input field and the component simultaneously, you can do it like this:
class Form extends React.Component {
constructor(props) {
super(props)
this.state = {
input: '',
submitted: false, // adding the flag
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({input: e.target.value});
}
handleSubmit(e) {
e.preventDefault();
this.setState({ submitted: true }); // set the flag on submit
console.log(this.state.input)
}
render() {
return(
<form>
<label>
Name:
<input type="text" value={this.state.input} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" onClick={this.handleSubmit} />
{this.state.submitted && (
<Fetch username={this.state.input} />
)}
</form>
);
}
}
Actually what you are doing is every time the user type a character, you are displaying Fetch component with the input's value passed in props.
With this and with the handleChange method
if (this.state.input) {
return <Fetch username={this.state.input} />
}
The condition here return true if input is different from "". So when a character is type it becomes true and displays it.
In your case what you want to do is to display the Fetch component when you are clicking on the submit button.
What you can do is create a state to manage it.
For example you could have this in your state :
this.state = {
input: '',
fetchIsVisibile: false,
};
Then in your handleSubmit just do this:
handleSubmit(e) {
this.setState({ fetchIsVisible: true }),;
e.preventDefault();
}
And the condition for display your fetch component would be using this new state instead of input state
if (this.state.fetchIsVisible) {
return <Fetch username={this.state.input} />
}
You can add state whether the form is submitted in the state and to check for it when rendering the component
if you want to check whether the form is submitted and the input is not empty you can use (this.state.submitted && this.state.input) instead
class Form extends React.Component {
constructor(props) {
super(props)
this.state = {
input: '',
submitted: false
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
this.setState({input: e.target.value});
}
handleSubmit(e) {
this.setState({
submitted: true
});
}
render() {
//Not sure how to check for this
if (this.state.submitted) {
return <div>
<div>FETCH COMPONENT</div>
<div>input: {this.state.input}</div>
</div>
}
return(
<form>
<label>
Name:
<input type="text" value={this.state.input} onChange={this.handleChange} />
</label>
<div>input: {this.state.input}</div>
<input type="submit" value="Submit" onClick={this.handleSubmit} />
</form>
);
}
}
ReactDOM.render(<Form />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
I have an input field where the user enters a name, and I then want this name to be display at all times on the navbar. After entering a name the user presses a button that takes them to a new screen via react-router-dom like this
<Link to="/events">
<button type="submit" className="btn btn-primary">Sign in</button>
</Link>
This is what I have right now
In my component with the input field
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
console.log(this.state);
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input
type="email"
className="form-control"
id="inputEmail3"
placeholder="Enter your username"
onChange={this.handleChange}/>
)
}
}
I removed anything that doesn't have to do with the particular input field, which is why the return statement looks the way it does.
With what I have now, I get the input field value as a state, but I'm not sure how to get that value in another component.
I then have a Navbar component where I have a simple <p className="">Username</p> where I want the name to be displayed.
Any help on how to achieve this?
I am building a very basic React application but having some issues with form inputs:
My state:
class App extends Component {
constructor(){
super();
this.state = {
books: [],
book:{
author:"",
title: ""
}
}
this.handleInputChange = this.handleInputChange.bind(this)
}
My form:
<form onSubmit={this.addBook}>
<input
name="author"
type="text"
placeholder="author"
value={this.state.book.author}
onChange={this.handleInputChange}
/><br/>
<input
name="title"
type="text"
placeholder="title"
value={this.state.book.title}
onChange={this.handleInputChange}
/><br/>
<input type="submit" />
<button>Update</button>
<button>Delete</button>
</form>
My event handler:
handleInputChange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
Still I am not able to digit in the input field. When I try to digit a value nothing happens and the input field is not updating properly. Any suggestions?
Thanks
Your book state is state.book.title and state.book.author, so you need to specify in setState that it's the state.book object that you want to update with the event.target.value.
Hopefully this will do the trick:
handleInputChange(event) {
this.setState({
book: {
...this.state.book,
[event.target.name]: event.target.value
},
});
}
When updating state for your nested book object, you need to make a copy of it, but with the property you want changed set to the new value. This is what the ellipsis notation helps with.
More info here: How do I setState for nested array?
The title/author properties are within the book object. It looks like you're only referencing state.author or state.title, but you need to reference state.book.title or state.book.author. Try this:
handleInputChange(event) {
this.setState({
book[event.target.name]: event.target.value
});
}