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.
Related
I am try trying to submit the form once the button is clicked, but the function is not triggering in React.
The only enquiry is on the submit button onclick=submitform.
So I can get the value and update it to the json arry
import React, { Component } from "react";
class Createcomponent extends Component {
constructor() {
super()
this.state={
firstname:"",
lastname:"",
phonenumber:""
}
this.ontextchange=this.ontextchange.bind(this)
this.submitform=this.submitform.bind(this)
}
componentDidMount() {
console.log("Component Mounted");
}
ontextchange(event) {
if(event.target.id==='fname') {
this.setState({firstname: event.target.value})
}
}
submitform() {
alert("trigger");
//console.log(this.state)
}
render(){
return (
<div>
<label for="fname">First name:</label>
<input type="text" id="fname" onChange={this.ontextchange} value={this.state.firstname} name="fname"/><br/>
<label for="lname">Last name:</label>
<input type="text" id="lname" onChange={this.ontextchange} value={this.state.lastname} name="lname"/><br/>
<label for="lname">PhoneNumber:</label>
<input type="text" id="phone" onChange={this.ontextchange} value={this.state.phonenumber} name="lname"/><br/>
<input type="submit" value="Submit"/>
<button onClick={this.submitform}>Submit</button>
</div>
);
}
}
export default Createcomponent
You have two "Submit" buttons. Clicking the right "Submit" button triggers the alert correctly using your code as it is.
The left "Submit" button, which is setup as a form submit by setting type = submit, doesn't do anything because there actually is no <form> in use. Setting up a form as I've added it to your code below, the left "Submit" button works too. I've also created this CodeSandbox for demonstration.
import React, { Component } from "react";
class Createcomponent extends Component {
constructor() {
super();
this.state = {
firstname: "",
lastname: "",
phonenumber: ""
};
this.ontextchange = this.ontextchange.bind(this);
this.submitform = this.submitFormButton.bind(this);
}
componentDidMount() {
console.log("Component Mounted");
}
ontextchange(event) {
if (event.target.id === "fname") {
this.setState({ firstname: event.target.value });
}
}
submitFormButton() {
alert("trigger");
//console.log(this.state)
}
submitFormOnSubmit(e) {
e.preventDefault();
alert("trigger");
}
render() {
return (
<form onSubmit={this.submitFormOnSubmit}>
<label for="fname">First name:</label>
<input
type="text"
id="fname"
onChange={this.ontextchange}
value={this.state.firstname}
name="fname"
/>
<br />
<label for="lname">Last name:</label>
<input
type="text"
id="lname"
onChange={this.ontextchange}
value={this.state.lastname}
name="lname"
/>
<br />
<label for="lname">PhoneNumber:</label>
<input
type="text"
id="phone"
onChange={this.ontextchange}
value={this.state.phonenumber}
name="lname"
/>
<br />
<input type="submit" value="Submit" />
<button onClick={this.submitFormButton}>Submit</button>
</form>
);
}
}
export default Createcomponent;
Make sure to use htmlFor instead of for in React on your label element.
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;
Please help me to understand where I am doing what mistake? I created CustomerForm React Component, which having few form fields. These form fields will add records and in another component will show records into table format.
Every thing is working fine for CustomerForm React Component, but if I am adding onSubmit function than form fields are not loading and I am getting console error as:-
Uncaught ReferenceError: onSubmit is not defined
at new CustomerForm (index.js:32590)
<button type="submit" className="btn btn-primary" onClick={ e => this.onSubmit(e)} > Submit </button>
Also please suggest any better way to write ReactJS code using Props & State...
// Let's import react for creating component
import React from "react";
// Create CustomerForm component
class CustomerForm extends React.Component{
// create constructor function for CustomerForm component
constructor(props){
// call super, so constructor function can connect with CustomerForm component
super(props);
// Use state add object with their property and value
this.state = {
firstName : "",
lastName : "",
phoneNo : "",
issue : "",
}
// Create changeData function
// changeData = e => {
// this.setState({
// [e.target.name] : e.target.value
// });
// };
onSubmit = e => {
e.preventDefault();
console.log(this.state);
}
} // close constructor function
render(){
return(
<form>
<div className="form-group">
<label htmlFor="fname">First name</label>
<input
type="text"
className="form-control"
id="fname"
placeholder="First name"
value={this.state.firstName}
onChange={e => this.setState({ firstName: e.target.value })}
/>
{/* call setState for change firstName value
question - I created changeData function which target name attribute and change value for form fields, but it's not working
onChange={e => this.changeData(e)}
*/}
</div>
<div className="form-group">
<label htmlFor="lname">Last name</label>
<input
type="text"
className="form-control"
id="lname"
placeholder="Last name"
value={this.state.lastName}
onChange={e => this.setState({ lastName: e.target.value })}
/>
{/* call setState for change lastName value */}
</div>
<div className="form-group">
<label htmlFor="phone">Phone no.</label>
<input
type="text"
className="form-control"
id="phone"
placeholder="Phone no."
value={this.state.phoneNo}
onChange={e => this.setState({phoneNo: e.target.value})}
/>
{/* call setState for change phoneNo value */}
</div>
<div className="form-group">
<label htmlFor="issue">Issue</label>
<textarea
className="form-control"
id="issue"
rows="3"
value={this.state.issue}
onChange={e => this.setState({issue: e.target.value})}
>
{/* call setState for change issue value */}
</textarea>
</div>
<button
type="submit"
className="btn btn-primary"
onClick={ e => this.onSubmit(e)}
>
Submit
</button>
</form>
);
}
}
export default CustomerForm;
You're declaring a variable named onSubmit on the constructor and trying to access it with this.onSubmit, like a property.
You can do this in your constructor:
this.onSubmit = e => {
e.preventDefault();
console.log(this.state);
}
The suggestion
A better way to accomplish this is extracting your onSubmit method to a class method, with makes your code more readable and more consistent. Would be something like this:
// Let's import react for creating component
import React from "react";
// Create CustomerForm component
class CustomerForm extends React.Component{
// create constructor function for CustomerForm component
constructor(props){
// call super, so constructor function can connect with CustomerForm component
super(props);
// Use state add object with their property and value
this.state = {
firstName : "",
lastName : "",
phoneNo : "",
issue : "",
}
}
/////////
/// Your submit handler is now a method in the CustomerForm class,
/// so you can access with the keyword "this"
onSubmit(e) {
e.preventDefault();
console.log(this.state);
}
render(){
return(
<form onSubmit={e => this.onSubmit(e)}>
{/* Note that I've changed your handler to form,
is usually better than put on a button, since you're using a form already */}
<div className="form-group">
<label htmlFor="fname">First name</label>
<input
type="text"
className="form-control"
id="fname"
placeholder="First name"
value={this.state.firstName}
onChange={e => this.setState({ firstName: e.target.value })}
/>
{/* call setState for change firstName value
question - I created changeData function which target name attribute and change value for form fields, but it's not working
onChange={e => this.changeData(e)}
*/}
</div>
<div className="form-group">
<label htmlFor="lname">Last name</label>
<input
type="text"
className="form-control"
id="lname"
placeholder="Last name"
value={this.state.lastName}
onChange={e => this.setState({ lastName: e.target.value })}
/>
{/* call setState for change lastName value */}
</div>
<div className="form-group">
<label htmlFor="phone">Phone no.</label>
<input
type="text"
className="form-control"
id="phone"
placeholder="Phone no."
value={this.state.phoneNo}
onChange={e => this.setState({phoneNo: e.target.value})}
/>
{/* call setState for change phoneNo value */}
</div>
<div className="form-group">
<label htmlFor="issue">Issue</label>
<textarea
className="form-control"
id="issue"
rows="3"
value={this.state.issue}
onChange={e => this.setState({issue: e.target.value})}
>
{/* call setState for change issue value */}
</textarea>
</div>
<button
type="submit"
className="btn btn-primary"
>
Submit
</button>
</form>
);
}
}
export default CustomerForm;
Controlled Components
Just one more thing I think it may be helpful to you (I've noted your comment about changeData) so if you not resolve the way to do controlled inputs, this minimalist example may help you, with a onChangeHandler I usually use:
import React from 'react';
export default class MyControlledComponent extends React.Component {
constructor(props){
super(props);
// Initiating the first value for our controlled component
this.state = {
name: ""
}
}
submitHandler(e) {
e.preventDefault();
console.log('Hi, ' + this.state.name + '!');
}
onChangeHandler(e) {
const { name, value } = e.target
/*
Here we using the name property of your input to
increase reuse of this function
*/
this.setState({
[name]: value
});
}
render(){
return (
<div className="my-app">
<form onSubmit={e => this.submitHandler(e)}>
<input type="text"
name="name"
value={this.state.name}
onChange={e => this.onChangeHandler(e)} />
<button>Send!</button>
</form>
</div>
)
}
}
Hope it helps!
Your onSubmit function is not bind either bind it in constructor or use fat arrow properly like
{(return)=>{functionname()}}
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>
}
}
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.