How can I handle redux form submission in child component? - reactjs

In all examples that I read, we always handle submission of the form from parent component.
For instance:
export default class ParentComponent extends React.Component{
constructor(){
super();
this.state = {
working: false,
users: []
}
}
handleSubmit(values){
//do something
}
render(){
return(
<div className="container">
<ReduxForm onSubmit={this.handleSubmit.bind(this)} {...this.props}/>
</div>
);
}
}
and in child component
class ReduxForm extends React.Component{
constructor(){
super();
}
render(){
const {handleSubmit, pristine, reset, submitting } = this.props;
return(
<div>
<h2>Hello, Redux form</h2>
<form onSubmit={handleSubmit}>
<div className="form-group">
<label htmlFor="firstName">First Name</label>
<Field name="firstName" component="input" type="text" className="form-control"/>
</div>
<div className="form-group">
<label htmlFor="lastName">Last Name</label>
<Field name="lastName" component="input" type="text" className="form-control"/>
</div>
<div className="form-group">
<button type="submit" className="btn btn-success">Submit</button>
</div>
</form>
</div>
);
}
}
I think we should handle the submission in ReduxForm (child component) for reusable (what if we have another page, use that form again and we have to handle submission every time?)
I tried to handle the submission in redux form way, but it's not success.
Any idea?
Thank you so much!

You can delegate the submission callback to the function of your choice
class ReduxForm extends React.Component{
constructor(){
super();
this.submit = this.submit.bind(this);
}
submit(values) {
alert('SUBMIT : ' + JSON.stringify(values));
}
render(){
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit(this.submit)}>
// ^^^^^^^^^^^
// Your submission handler
// ...
</form>
}
}

Related

Why data is not rendered on refresh in react js with asynchronous call?

I am creating edit form.First i have to get data to edit form and i am calling it in componentDidMount().Please see code below.
import React from 'react';
import CompanyForm from './CompanyForm';
import { connect } from 'react-redux';
import { companyActions } from '../../../redux/actions/company-action';
class EditCompanyPage extends React.Component {
constructor(props){
super(props);
};
componentDidMount () {
const { id } = this.props.match.params
const { dispatch } = this.props;
dispatch(companyActions.getCompany(id));
}
render(){
const {editUser } = this.props;
return(
<div>
<h1>Edit Company</h1>
{
editUser && <CompanyForm handleActionParent={this.handleAction} companyDataFP={editUser} />
}
</div>
);
};
}
function mapStateToProps(state) {
const { editUser } = state.companyReducer;
return {
editUser
};
}
const EditCompany = connect(mapStateToProps)(EditCompanyPage);
export default EditCompany;
see code for CompanyForm component below:
import React from 'react';
class CompanyForm extends React.Component {
constructor(props){
super(props);
this.state = {
company :{
name : this.props.companyDataFP.name || '',
address1 : this.props.companyDataFP.address1 || '',
}
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
};
handleChange(e) {
const { name, value } = e.target;
const newState = Object.assign({}, this.state);
newState.company[name] = value;
this.setState(newState);
}
handleSubmit(e) {
e.preventDefault();
return false;
}
render(){
return(
<div className="col-md-12">
<form onSubmit={this.handleSubmit}>
<div className="row">
<div className="col-md-6">
<div className='form-group'>
<label htmlFor="name">Name</label>
<input type="text" name="name" className="form-control" onChange={this.handleChange} value={this.state.company.name} />
</div>
</div>
<div className="col-md-6">
<div className='form-group'>
<label htmlFor="address1">Address 1</label>
<input type="text" name="address1" className="form-control" onChange={this.handleChange} value={this.state.company.address1} />
</div>
</div>
</div>
<div className="row">
<div className="col-md-12">
<div className='form-group'>
<input type="submit" className="btn btn-info" value="submit" />
</div>
</div>
</div>
</form>
</div>
);
};
}
export default CompanyForm;
It works fine when i access this form with
<Link to="/edit-form/:id" >Edit</Link>
but when i refresh the current page then values are not rendering into form to edit.
I am using redux approach for state management, please guide me i am new to react.
Probably ComponyForm initializes form on its componentDidMount lifecycle function, so when editUser arrives nothing will change.
A way to handle this is changing:
<CompanyForm handleActionParent={this.handleAction} companyDataFP={editUser} />
to:
{editUser.name && <CompanyForm handleActionParent={this.handleAction} companyDataFP={editUser} />}

unable to get enter and get value in REACT.js

I am new to ReactJS and trying to build a sample application
I am unable to get enter the value in textbox and unable to get the value in alert. Am I doing something wrong. I have tried the example given on React.Js Form, but not working.
import React, { Component } from "react";
class AddNewStudent extends Component {
constructor(props) {
super(props);
this.state = {value:''};
this.OnSubmit = this.OnSubmit.bind(this);
}
OnSubmit(event){
alert('name value is : '+this.state.value);
event.preventDefault();
}
render(){
return(
<div>
<form onSubmit={this.OnSubmit}>
<fieldset className="Student-Form" id={this.props.id}>
<legend className="Legend">Add mew student</legend>
<div>
<div className="Block">
<div className="Float-Left">
<label>
<span>Name : </span>
<input type="text" value={this.state.value} />
</label>
</div>
</div>
<div className="clearFix" />
<div className="Block">
<div className="Float-None">
<label>
<input type="submit" value="Save" />
</label>
</div>
</div>
</div>
</fieldset>
</form>
</div>
);
}
}
export default AddNewStudent;
please change :
<input type="text" value={this.state.value} />
to:
<input type="text" value={this.state.value} onChange = {this.onChange}/>
In your class, add the 'onChange' function:
onChange(e){
this.setState({
value: e.target.value
})
}
and in your constructor:
this.onChange = this.onChange.bind(this)
Edit 1:
please check my codepen here
Edit 2:
If you have too many inputs, you can use a function like this:(it's just a rough example, in real world I'll create a new component to handle this together)
//in your constructor
this.state = {}
//in class 'controlled component way'
createInput(num){
let inputArray = []
for(let i = 0; i < num; i ++){
inputArray.push(<input key = {i} name = {i} onChange = {this.onChange} value = {this.state[i] || ''} />)
}
return inputArray
}
onChange(e){
let key = e.target.name
let newState = {}
newState[key] = e.target.value
this.setState(newState)
}
// in your render function
return <div>
{this.createInput(100)}
</div>
check my codepen here for this example
and of course you can also do this using uncontrolled component.
controlled component and uncontrolled
You can either bind onChange event to your input or setState when submiting the value , you cant change the state like that
Change your code to something like this
import React, { Component } from "react";
class AddNewStudent extends Component {
constructor(props) {
super(props);
this.state = {value:''};
this.OnSubmit = this.OnSubmit.bind(this);
}
OnSubmit(event){
this.setState({value: this.refs.infield.value},()=>{
alert('name value is : '+this.state.value);
})
event.preventDefault();
}
render(){
return(
<div>
<form onSubmit={this.OnSubmit}>
<fieldset className="Student-Form" id={this.props.id}>
<legend className="Legend">Add mew student</legend>
<div>
<div className="Block">
<div className="Float-Left">
<label>
<span>Name : </span>
<input type="text" ref = "infield"/>
</label>
</div>
</div>
<div className="clearFix" />
<div className="Block">
<div className="Float-None">
<label>
<input type="submit" value="Save" />
</label>
</div>
</div>
</div>
</fieldset>
</form>
</div>
);
}
}
export default AddNewStudent;
Hi to get the value add a name to the input and an onChange function to set the value to the state and then do what evere you want in onsubmit function
I cant write you a working code now because I'm using my phone but my this Will help
onfieldchange(e) {
this.setState({[e.target.name]: e.target.value});
}
onaSubmit(){
//do your code here
}
....
....
<input type="text" name="firstName" value={this.state.firstName} />
Hope this help you
There are two ways to handle form elements in reactjs:
Controlled and uncontrolled components(using refs).In controlled component approach ,you have to add the state of the input field to the input field value and onChange event to it, which is the one you are trying to do.Here is the working code.
import React, { Component } from "react";
class AddNewStudent extends Component {
constructor(props) {
super(props);
this.state = {
firstname:''
};
this.OnSubmit = this.OnSubmit.bind(this);
this.OnChange = this.OnChange.bind(this);
}
OnSubmit(event){
alert('name value is : '+this.state.firstname);
event.preventDefault();
}
OnChange(){
this.setState({
[e.target.name] : [e.target.value]
});
}
render(){
return(
<div>
<form onSubmit={this.OnSubmit}>
<fieldset className="Student-Form" id={this.props.id}>
<legend className="Legend">Add mew student</legend>
<div>
<div className="Block">
<div className="Float-Left">
<label>
<span>Name : </span>
<input type="text"
name="firstname"
value={this.state.firstname}
OnChange={this.OnChange}
/>
</label>
</div>
</div>
<div className="clearFix" />
<div className="Block">
<div className="Float-None">
<label>
<input type="submit" value="Save" />
</label>
</div>
</div>
</div>
</fieldset>
</form>
</div>
);
}
}
export default AddNewStudent;

update list array from child component

new react user here.
i am trying to access form data in my parent app from the child form. I am trying to alert or console the data from the parent so I can visually see what was typed in the form. Once I can access the data in the parent I will try and move it to my list array.
PARENT
class App extends Component {
constructor() {
super();
this.state = {
lists: [],
items: {}
};
}
handleAddList(s) {
alert('I am calling function from child')
console.log(this.refs.id.value) // this errors out on me
}
render() {
return (
<div className="App">
<AddList addList={this.handleAddList.bind(this)} />
<div id="listsDiv" className="List">
<Lists lists={this.state.lists} items={this.state.items} addItem {this.handleAddItem.bind(this)} />
</div>
</div>
);
}
}
CHILD
class AddList extends Component {
handleSubmit(e) {
e.preventDefault();
alert(this.refs.id.value)
this.props.addList()
}
render() {
return (
<div id="addListDiv">
<form onSubmit={this.handleSubmit.bind(this)}>
<div id='addList'>
<label>What will be on your next list?
<input type='text' ref='id' id='newID'></input>
</label>
</div><br />
<input type='submit' value='Create List' />
</form>
</div>
);
}
}
You should set the ref on the input using a callback, like this:
<input type='text' ref={input => { this.input = input; }} id='newID'></input>
Then access it in your event handler like this:
alert(this.input.value);
However, if you are new to React, you should try using controlled components before you try to use refs.
https://reactjs.org/docs/forms.html
CHILD
import ReactDOM from 'react-dom';
class AddList extends Component {
handleSubmit(e) {
e.preventDefault();
var day = ReactDOM.findDOMNode(this.refs.id).value.trim();
this.props.addList(day);
}
render() {
return (
<div id="addListDiv">
<form onSubmit={this.handleSubmit.bind(this)}>
<div id='addList'>
<label>What will be on your next list?
<input type='text' ref='id' id='newID'></input>
</label>
</div><br />
<input type='submit' value='Create List' />
</form>
</div>
);
}
}
PARENT
class App extends Component {
handleAddList(args) {
console.log(args);
}
render() {
return (
<div className="App">
<AddList addList={this.handleAddList.bind(this)} />
</div>
);
}
}
Edit it a little to work for you.

How to reset form from higher order component in React?

Iam doing an app in react.js in which iam passing a component to higher order component.Now after form submission in PersonalInformation component the form needs to reset which is not happening.It is not happening by refs.
class PersonalInformation extends Component{
render(){
return(
<div>
<h3>Personal Information</h3>
<Form onSubmit={this.props.handleSubmit} ref="form" name="form">
<fieldset disabled={this.props.disabled}>
<Input type="text" name="firstName" title="FirstName" value=""/><br/>
<Input type="text" name="lastName" title="LastName" value=""/><br/>
<Input type="text" name="fatherName" title="Fathers's Name" value=""/><br/>
<Input type="text" name="motherName" title="Mother's Name" value=""/><br/>
</fieldset>
<button className="btn btn-default">{this.props.buttonName}</button>
</Form>
</div>
)
}
}
Now the Higher Order component is:
var MyHoc = function(AbstractComponent){
return class extends React.Component {
constructor(props){
super(props);
this.state={
buttonName:'Edit',
disabled:true,
anotherForm:false
}
this.handleSubmit=this.handleSubmit.bind(this);
this.newForm=this.newForm.bind(this);
}
handleSubmit(data){
this.setState({
buttonName:'Save',
disabled:false
})
if(!this.state.disabled){
console.log(data);
this.refs.form.reset();
}
}
newForm(){
this.setState({
anotherForm:true
})
}
render() {
return <AbstractComponent {...this.state} handleSubmit={this.handleSubmit}
newForm={this.newForm} />;
}
}
}
export default MyHoc(PersonalInformation);
You cannot access refs from different components. this.refs refers to the ref defined in that particular component.
You can pass a callback method in handleSubmit function and handlesubmit will call that method when it want to reset form. Something like this
handleSubmit(data, resetFormCallback){
this.setState({
buttonName:'Save',
disabled:false
})
if(!this.state.disabled){
console.log(data);
resetFormCallback();
}
}
And then in your child component you pass a callback method while calling handleSubmit
class PersonalInformation extends Component{
resetForm = () => {
this.refs.form.reset();
}
render(){
return(
<div>
<h3>Personal Information</h3>
<Form onSubmit={(data) => {this.props.handleSubmit(data, this.resetForm)}} ref="form" name="form">
<fieldset disabled={this.props.disabled}>
<Input type="text" name="firstName" title="FirstName" value=""/><br/>
<Input type="text" name="lastName" title="LastName" value=""/><br/>
<Input type="text" name="fatherName" title="Fathers's Name" value=""/><br/>
<Input type="text" name="motherName" title="Mother's Name" value=""/><br/>
</fieldset>
<button className="btn btn-default">{this.props.buttonName}</button>
</Form>
</div>
)
}
}
this refers to the component in hand. You are looking for a ref on another component, so that's not going to work.
At this line: this.refs.form.reset(); instead set some state like resetForm:true, which then gets passed down to your child component. Then you can reset your form from the component it lives in based on the state that gets passed to it via props.

Redux Submitting a form from Presentation Component to Container Component

I am using a simple Login Form and i have LoginContainer (Container Component ) and Login (presentation component) and i am trying to submit the form and access the data in the Container Component.
Here is the code i have
Login.js:
export default class Login extends React.Component {
constructor() {
super();
}
render() {
return (
<div className="login jumbotron center-block">
<h1>Login</h1>
<form role="form">
<div className="form-group">
<label htmlFor="username">Username</label>
<input type="text" className="form-control" ref="username" placeholder="Username" />
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input type="password" className="form-control" ref="password" placeholder="Password" />
</div>
<div className="form-group">
<button type="submit" className="btn btn-default" onClick={()=>{this.props.login(this.refs.username,this.refs.password)}}>Submit</button>
</div>
</form>
</div>
);
}
}
And the container component is:
class LoginContainer extends React.Component{
constructor(props){
super(props);
}
render(){
return(
<div>
<Login login={this.loginUser}/>
</div>
);
}
}
function mapStateToProps(state){
return state;
}
function mapDispatchToProps(dispatch){
return{
login : (username,password) => {
console.log('mapDispatchToProps : username=['+username+'] password=['+password+']');
}
}
}
export default connect(mapStateToProps,mapDispatchToProps)(LoginContainer);
The above code doesn't work as in the event handler for the submit i cannot access this.refs
Uncaught ReferenceError: refs is not defined
I don't want to maintain the state of Login Component. I can easily create state with username and password in Login and use setState with onclick or onchange on username and password controls.
Is there way i can send the data of form elements from Presentation component to Container component with a form submit ?
Thanks
You need to make event handling methods in Login.js file and bind them to the component context using bind function in the constructor.
export default class Login extends React.Component {
constructor() {
super();
this.login = this.login.bind(this);
}
login() {
this.props.login(this.refs.username,this.refs.password)
}
render() {
return (
<div className="login jumbotron center-block">
<h1>Login</h1>
<form role="form">
<div className="form-group">
<label htmlFor="username">Username</label>
<input type="text" className="form-control" ref="username" placeholder="Username" />
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input type="password" className="form-control" ref="password" placeholder="Password" />
</div>
<div className="form-group">
<button type="submit" className="btn btn-default" onClick={this.login}>Submit</button>
</div>
</form>
</div>
);
}
}
This way you dont maintain state of Logic component, you simply use props passed from the container.

Resources