ReactJS - pass input values from child to parent - reactjs

child component
import React, { Component } from 'react'
export default class Login extends Component {
constructor (props) {
super(props);
this.state = {Id: '',name: '',gender: ''};
this.show = this.show.bind(this);
}
show (event) {
if (this.state.Id === "123456" && this.state.name !== '' && this.state.gender !== '') {
this.props.show();
alert('you are login');
console.log('A ID was submitted: ' + this.state.Id);
console.log('A Name was submitted: ' + this.state.name);
console.log('A Gender was submitted: ' + this.state.gender);
} else {
alert('Please enter your valid id,Your Name & Gender');
}
event.preventDefault();
}
render () {
return (
<div className="login">
<form onSubmit={ this.show.bind(this) }>
<div>
<label>Your ID:</label>
<input type="text" onChange={ event => this.setState({ Id: event.target.value }) } placeholder="Enter your ID" />
</div>
<br />
<div>
<label>Your Name:</label>
<input type="text" onChange={ event => this.setState({ name: event.target.value }) } placeholder="Enter your Name" />
</div>
<br />
<div>
<label>Your Gender:</label>
<label>Female:</label>
<input type="radio" name="gender" value="Female" onChange=
{ event => this.setState({ gender: event.target.value }) } />
<label>Male:</label>
<input type="radio" name="gender" value="Female" onChange={ event => this.setState({ gender: event.target.value }) } />
</div>
<input type="submit" value="Submit" onClick={ this.props.comingvalue } />
</form>
</div>
)
}
}
parent component
class App extends Component {
constructor (props) {
super(props);
this.state = { Id: '', name: '', gender: '' };
}
getvalue () {
console.log('getting values as props');
this.setState({ Id: this.state.Id });
this.setState({ name: this.state.name });
this.setState({ gender: this.state.gender });
}
render () {
return (
<div className="App">
<Login comingvalue={ this.getvalue } />
<button type="button" className="btn btn-primary" onClick=
{ this.handleLogin }>Sign In</button>
</div>
);
}
}
export default App;
now here is the my question i want that when i enter value in my child component i get those values in parent compnent how i can get this please help..'i thing you peeple should know that i cut alot of code from above code there is possibilty of any other error but i want to know only one thing which i mention above i want child coponents value in parent component.. please suggest me right solution..thanks

Just a pointer for future posts: the less code the better and please, for the love of God, make sure the formatting is correct.
A standard pattern in React for passing information back up the tree is to pass children a callback as a prop.
parent
class Parent extends React.Component {
onChildCallback = (data) => {
alert(data)
}
render() {
return (
<div>
...
<Child onAction={this.onChildCallback}/>
</div>
)
}
}
child
class Child extends React.Component {
render() {
return (
<button onClick={() => this.props.onAction('hello from the child')}>
Click Me!
</button>
)
}
}
this is, of course, simplified, but you can extend it however you like. Some things to watch out for:
make sure you're either binding the callback in the parent or using arrow functions (in this case, I'm using a ES7 class property)
if you need data from a child of a child, you need to chain these... you can get away with using context, but ... don't. Just don't.

Related

Passing submitted form data to another component

I have the following code, it basically accepts some basic input and when submit button is clicked user is notified with an alert, state is constantly being updated via onChange event. What i wonder is can i somehow pass the retrieved data to another component inside the event handler for submit button (which i have called handleFormSubmit)? I have recently seen react has something called 'context' ...maybe that would be best here? Advice please? :)
class Form extends Component {
constructor(props) {
super(props)
this.state = {
username: '',
comments: '',
topic: 'react'
}
this.handleUsernameChange = this.handleUsernameChange.bind(this);
this.handleCommentsChange = this.handleCommentsChange.bind(this);
this.handleTopicChange = this.handleTopicChange.bind(this);
this.handleFormSubmit = this.handleFormSubmit.bind(this);
}
handleUsernameChange(event){
this.setState({
username: event.target.value
},
() =>{
console.log(this.state.username)
})
}
handleCommentsChange(event){
this.setState({
comments: event.target.value
},
() =>{
console.log(this.state.comments)
})
}
handleTopicChange(event){
this.setState({
topic: event.target.value
},
() =>{
console.log(this.state.topic)
})
}
handleFormSubmit(event){
event.preventDefault();
alert(`${this.state.username} ${this.state.comments} ${this.state.topic}`);
}
render() {
return (
<form onSubmit={this.handleFormSubmit}>
<div>
<label>Username</label>
<input type='text' value={this.state.username} onChange={this.handleUsernameChange}/>
</div>
<div>
<textarea value={this.state.comments} onChange={this.handleCommentsChange}></textarea>
</div>
<div>
<select value={this.state.topic} onChange={this.handleTopicChange}>
<option value="react">React</option>
<option value="angular">Angular</option>
<option value="vue">Vue</option>
</select>
</div>
<button>Submit</button>
</form>
)
}
}
Hi all i made some changes and got something working, added extra state attribute called dataSubmitted set it to false then only after i submit the data is child (which i called AcceptFormData) allowed to render and i pass the state attributes as props. I do not know if this is a good approach or not but it works and no console errors.
class Form extends Component {
constructor(props) {
super(props)
this.state = {
username: '',
comments: '',
topic: 'react',
dataSubmitted: false
}
this.handleUsernameChange = this.handleUsernameChange.bind(this);
this.handleCommentsChange = this.handleCommentsChange.bind(this);
this.handleTopicChange = this.handleTopicChange.bind(this);
this.handleFormSubmit = this.handleFormSubmit.bind(this);
}
handleUsernameChange(event){
this.setState({
username: event.target.value
},
() =>{
console.log(this.state.username)
})
}
handleCommentsChange(event){
this.setState({
comments: event.target.value
},
() =>{
console.log(this.state.comments)
})
}
handleTopicChange(event){
this.setState({
topic: event.target.value
},
() =>{
console.log(this.state.topic)
})
}
handleFormSubmit(event){
event.preventDefault();
this.setState({
dataSubmitted: true
})
}
render() {
if(this.state.dataSubmitted === false){
return (
<form onSubmit={this.handleFormSubmit}>
<div>
<label>Username</label>
<input type='text' value={this.state.username} onChange={this.handleUsernameChange}/>
</div>
<div>
<textarea value={this.state.comments} onChange={this.handleCommentsChange}></textarea>
</div>
<div>
<select value={this.state.topic} onChange={this.handleTopicChange}>
<option value="react">React</option>
<option value="angular">Angular</option>
<option value="vue">Vue</option>
</select>
</div>
<button>Submit</button>
</form>
)
}else{
return (
<AcceptFormData username={this.state.username} comments={this.state.comments} topic={this.state.topic}/>
)
}
}
}
export default Form

pass object to setState fails

I created my own web-app of posts where you able to add,delete and update posts. Right now when I try to add a post and pass the inputs value throw a function and then execute 'setState' I get an error, something is wrong in the way I do it. could you help out?
I could just remove the root object from the state ('post') and just use the title,body as for themselfs. But I want to structure it this way: Post:{title,body}
import React, { Component } from 'react';
export class addPost extends Component {
state = {
post: {
title: '',
body: ''
}
};
handleChange = e => {
this.setState({ post[e.currentTarget.id]: e.currentTarget.value });
console.log(this.state);
};
handleSubmit = () => {};
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
Enter title:
<input
type="text"
value={this.state.title}
onChange={this.handleChange}
id="title"
/>
Enter body:
<input
type="text"
value={this.state.body}
onChange={this.handleChange}
id="body"
/>
</form>
</div>
);
}
}
export default addPost;
I expect to pass this object post:{title:'sometext',body:'sometext'}
You need to fix on two places
Where you are setting state
Where you are accessing state in input
handleChange = e => {
this.setState(prevState => ({
post: { ...prevState.post, [e.target.id]: e.target.value }
}));
};
<input value={this.state.post.title />
<input value={this.state.post.body} />
Made a sandbox for you: https://codesandbox.io/s/p2w7765j0
Most conventions are to use the name property for your inputs and map them using event.target.name
import React, { Component } from "react";
class AddPost extends Component {
state = {
post: {
title: "",
body: ""
}
};
handleChange = event => {
this.setState(
{
post: {
...this.state.post,
[event.target.name]: event.target.value
}
},
() => console.log(this.state)
);
};
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
Enter title:
<input
type="text"
value={this.state.post.title}
onChange={this.handleChange}
name="title"
/>
Enter body:
<input
type="text"
value={this.state.post.body}
onChange={this.handleChange}
name="body"
/>
</form>
</div>
);
}
}
export default AddPost;

How to dynamically generate pair of input fields using reactjs

I have tried the following code to create a react form to dynamically generate input fields to enter the series of person's name one by one. But user needs to enter the first name and last name instead of just name. So that, the form needs to generate pair of dynamic input fields. I am new to react. Can anyone please give an hint on how to accomplish this.
Note : The following code has been taken from the stackoverflow answer of #Mayank Shukla at How to implement a dynamic form with controlled components in React.JS?.
class App extends React.Component {
constructor(props) {
super(props);
this.state = { values: [] };
this.handleSubmit = this.handleSubmit.bind(this);
}
createUI(){
return this.state.values.map((el, i) =>
<div key={i}>
<input type="text" value={el||''} onChange={this.handleChange.bind(this, i)} />
<input type='button' value='remove' onClick={this.removeClick.bind(this, i)}/>
</div>
)
}
handleChange(i, event) {
let values = [...this.state.values];
values[i] = event.target.value;
this.setState({ values });
}
addClick(){
this.setState(prevState => ({ values: [...prevState.values, '']}))
}
removeClick(i){
let values = [...this.state.values];
values.splice(i,1);
this.setState({ values });
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.values.join(', '));
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
{this.createUI()}
<input type='button' value='add more' onClick={this.addClick.bind(this)}/>
<input type="submit" value="Submit" />
</form>
);
}
}
ReactDOM.render(<App />, document.getElementById('container'));
Idea is, maintain an array of object in state variable. Each object will have two keys firstName and secondName (you can add more fields). Treat each object as a single unit and for all the keys render input element, and whenever user will click on add more, add one more object/entry the the array with two keys.
Working Fiddle.
Working Snippet:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
users: [{firstName: "", lastName: ""}]
};
this.handleSubmit = this.handleSubmit.bind(this);
}
addClick(){
this.setState(prevState => ({
users: [...prevState.users, { firstName: "", lastName: "" }]
}))
}
createUI(){
return this.state.users.map((el, i) => (
<div key={i}>
<input placeholder="First Name" name="firstName" value={el.firstName ||''} onChange={this.handleChange.bind(this, i)} />
<input placeholder="Last Name" name="lastName" value={el.lastName ||''} onChange={this.handleChange.bind(this, i)} />
<input type='button' value='remove' onClick={this.removeClick.bind(this, i)}/>
</div>
))
}
handleChange(i, e) {
const { name, value } = e.target;
let users = [...this.state.users];
users[i] = {...users[i], [name]: value};
this.setState({ users });
}
removeClick(i){
let users = [...this.state.users];
users.splice(i, 1);
this.setState({ users });
}
handleSubmit(event) {
alert('A name was submitted: ' + JSON.stringify(this.state.users));
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
{this.createUI()}
<input type='button' value='add more' onClick={this.addClick.bind(this)}/>
<input type="submit" value="Submit" />
</form>
);
}
}
ReactDOM.render(<App />, document.getElementById('container'));
<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="container" />
Try this
state = {
number: [""],
dataArr: []
}
render() {
return (
<div>
<div onClick={()=>this.setState(prevState => ({number: [...prevState.number, ""]}))}>Add More element</div>
{this.state.number.map((e, i)=> {
return (
<input value={this.state.number[i]} onChange={(data) => this.setState({dataArr: update(this.state.dataArr, {i: {$set: data}})})} />
)
})}
</div>
)
}
You will have to handle the data inside this.state.dataArr. For instance, this.state.dataAtt[0] will contain the starting value in input field before user presses "Add More Element" button and then when user presses the same button again data will be added in this.state.dataArr[1] and so on.
You will need react-addons-update lib.

More compact way to write onChange handler for form with many inputs that affect nested state properties?

What is a more compact and more easy way to write a handleChange function for multiple input than the following:
import React from "react";
function initialState() {
return ({
customer: {
name: '',
primaryContactPerson: {
name: '',
email: ''
}
}
})
}
export default class AddCustomerForm extends React.Component {
constructor(props) {
super(props);
this.state = initialState();
this.handleChange = this.handleChange.bind(this);
}
handleChange(event, field) {
console.log(event.target.name);
switch(event.target.name) {
case 'customer.name':
console.log(1);
this.setState({
this: {
customer: {
name: event.target.value
}
}
})
break;
case 'customer.primaryContactPerson.name':
console.log(2);
this.setState({
this: {
customer: {
primaryContactPerson: {
name: event.target.value
}
}
}
})
break;
case 'customer.primaryContactPerson.email':
this.setState({
this: {
customer: {
primaryContactPerson: {
email: event.target.value
}
}
}
})
break;
default:
break;
}
this.setState({[event.target.name]: event.target.value});
}
render() {
return (
<div className='section section--full-width'>
<h1>Add Customer</h1>
<form onSubmit={this.handleSubmit}>
<div className='form__row'>
<label>
Customer name
</label>
<input type="text" name="customer.name" value={this.state.customer.Name} onChange={this.handleChange} />
</div>
<div className='form__row'>
<label>
Contact person
</label>
<input type="text" name="customer.primaryContactPerson.name" value={this.state.customer.primaryContactPerson.name} onChange={this.handleChange} />
</div>
<div className='form__row'>
<label>
Contact details
</label>
<input type="text" name="customer.primaryContactPerson.email" value={this.state.customer.primaryContactPerson.email} onChange={this.handleChange} />
</div>
<div>
<input type="submit" value="Add" />
</div>
</form>
</div>
);
}
}
I have tried the following method that does not work for nested objects:
handleChange(event, field) {
this.SetState({event.targetname: event.target.value})
}
One dirty hack is using lodash _.set Link. This is not the recommended method only a workaround.
you can use
const tmp = this.state;
_.set(tmp, event.target.name, event.target.value);
this.setState({ customer: tmp.customer });
if you want to avoid direct state mutation you can also use
const tmp = _.cloneDeep(this.state)
this process will be slower.

How to fetch input from text box and print in React?

I am new to React trying to write a very simple project that fetches input of both text boxes and when button is clicked, the 'data' in text boxes is printed on paragraph.
How do I fetch text's in input text boxes when button is clicked?
class Input extends Component {
state = {
tagged: false,
message: '',
}
handleClick(e) {
this.setState({tagged: true});
e.preventDefault();
console.log('The link was clicked.');
}
render() {
return (
<div id="id" style={divStyle}>
<p> hello </p>
<input
style = {textStyle}
placeholder="user#email.com"
type="text">
</input>
<input
style = {textStyle}
placeholder="tag"
type="text">
</input>
<button
onClick={(e) => this.handleClick(e)}
style={buttonStyle}>
{this.state.tagged ? 'Tagged' : 'Tag ' }
</button>
<p>
{this.state.tagged ? 'Clicked' : 'Still' }
</p>
</div>
)
}
}
You can add onChange event handler in each input.
class Input extends Component {
state = {
tagged: false,
message: '',
input1: '',
input2: '',
}
handleClick(e) {
// access input values in the state
console.log(this.state) // {tagged: true, input1: 'text', input2: 'text2'}
this.setState({tagged: true});
e.preventDefault();
console.log('The link was clicked.');
}
handleInputChange = (e, name) => {
this.setState({
[name]: e.target.value
})
}
render() {
return (
<div id="id" style={divStyle}>
<p> hello </p>
<input
style = {textStyle}
placeholder="user#email.com"
type="text"
onChange={(e) => this.handleInputChange(e, 'input1')}
>
</input>
<input
style = {textStyle}
placeholder="tag"
type="text"
onChange={(e) => this.handleInputChange(e, 'input2')}
>
</input>
<button
onClick={(e) => this.handleClick(e)}
style={buttonStyle}>
{this.state.tagged ? 'Tagged' : 'Tag ' }
</button>
<p>
{this.state.tagged ? 'Clicked' : 'Still' }
</p>
</div>
)
}
}
There are two different ways of working with react inputs - you can either make them controlled or uncontrolled. When you say fetch text from inputs, this is called uncontrolled components and means that form data is handled by the DOM itself and not by react.
This is achieved by using ref and literally getting a reference to your input and fetching its value when you need it. you can read more about this approach in react docs.
According to react docs, it is recommended using controlled components
In most cases, we recommend using controlled
components to implement forms. In a controlled
component, form data is handled by a React component.
This means that you don’t use references to the inputs and instead handle changes of your inputs with an event handler and update state with the new values that the user has entered into the input fields. According to react docs here is how react handles form with controlled components:
the React component that
renders a form also controls what happens in that form on subsequent
user input. An input form element whose value is controlled by React in this way is called a “controlled component”.
In your case you can do this if you choose controlled inputs:
class ControlledInput extends React.Component {
constructor(props) {
super(props);
this.state = {
tagged: false,
firstInput: '',
secondInput: ''
}
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({ [event.target.name]: event.target.value });
}
handleClick(e) {
this.setState({ tagged: true });
e.preventDefault();
console.log('The link was clicked.');
}
render() {
const { firstInput, secondInput, tagged } = this.state;
return (
<div id="id">
{tagged && <p>{firstInput} {secondInput}</p> }
<input
value={firstInput}
name="firstInput"
onChange={this.handleChange}
type="text" />
<input
value={secondInput}
name="secondInput"
onChange={this.handleChange}
type="text" />
<button onClick={(e) => this.handleClick(e)}>
{tagged ? 'Tagged' : 'Tag '}
</button>
</div>
)
}
}
Here you put the inputs' values on state and update state when the user writes something in your inputs. If you however want to use uncontrolled components you can do it this way:
class UncontrolledInput extends React.Component {
state = {
tagged: false,
message: '',
}
handleClick(e) {
e.preventDefault();
const messageFromInputs = `${this.firstInput.value} ${this.secondInput.value}`;
this.setState({ tagged: true, message: messageFromInputs });
}
render() {
return (
<div id="id">
<p>{this.state.message}</p>
<input ref={(input) => this.firstInput = input} type="text" />
<input ref={(input) => this.secondInput = input} type="text" />
<button onClick={(e) => this.handleClick(e)}>
{this.state.tagged ? 'Tagged' : 'Tag '}
</button>
<p>
{this.state.tagged ? 'Clicked' : 'Still'}
</p>
</div>
)
}
}
Here you will actually fetch values from your inputs when the button is clicked.
I made a working example with both ways on codesandbox.

Resources