Error too much recursion using meteor and react - reactjs

I am trying to make a simple component in React to fill a form, but when I run it the console show me the error too much recursion
I already try to remove the event.preventDefault() on the handleSubmitbut that didn't work, I alse try to encapsulate the form using {this.props.currentUser ? (<form>...</form>) : ""
My code is the next one:
<form onSubmit={this.handleSubmit.bind(this)}>
<div className="form-group">
<label htmlFor="productName">Product name:</label>
<input
className="form-control"
type="text"
ref="productName"
required
/>
</div>
<div className="form-group">
<label htmlFor="productName">Product description:</label>
<input
className="form-control"
type="text"
ref="productDescription"
required
/>
</div>
<div className="form-group">
<label htmlFor="productName">Minimum amount increase</label>
<input
className="form-control"
type="text"
ref="minIncrease"
required
/>
</div>
<input className="btn btn-primary" type="submit" value="Submit" />
</form>
And the handleSubmit
handleSubmit(event) {
event.preventDefault();
// Find the txt field via React ref
const productName = ReactDOM.findDOMNode(this.refs.productName);
const productDescription = ReactDOM.findDOMNode(
this.refs.productDescription
);
const minIncrease = ReactDOM.findDOMNode(this.refs.minIncrease);
Meteor.call(
"auctions.insert",
productName,
productDescription,
minIncrease
);
Auctions.insert({
productName, // product name
productDescription, // product description
minIncrease, // minimum increase
value: 0, // initial value
winner: "", // actual winner
owner: Meteor.userId, // _id of logged in user
username: Meteor.user().username, // username of logged in user
createAt: new Date() // current time
});
// Clear form
ReactDOM.findDOMNode(this.refs.productName).value = "";
ReactDOM.findDOMNode(this.refs.productDescription).value = "";
ReactDOM.findDOMNode(this.refs.minIncrease).value = "";
}

I find the error, it was that in the handleSubmit it was missing .value.trim()
The correct code is:
handleSubmit(event) {
event.preventDefault();
// Find the txt field via React ref
const productName = ReactDOM.findDOMNode(
this.refs.productName
).value.trim();
const productDescription = ReactDOM.findDOMNode(
this.refs.productDescription
).value.trim();
const minIncrease = ReactDOM.findDOMNode(
this.refs.minIncrease
).value.trim();
...
}

Related

React How do I extract data from a form when triggering onSubmit event?

I am messing around with Riot's API that allows getting information of a player by the player's name. I am trying to get an API key (I only got a 24 hour key) and the target player's name from users' input.
export function PlayerSearch() {
function handlesubmit(e) {
console.log(e.target);
e.preventDefault();
}
return (
<div className='player'>
<div className='inputfield'>
<form onSubmit={handlesubmit} method='GET' autoComplete="off">
<div>
<label htmlFor="key">Your API key:</label>
<input
placeholder='Your API key'
onFocus={(e)=>{e.target.placeholder=''}}
type="text"
id="key"
name="key" />
</div>
<div>
<label htmlFor="name">Player name:</label>
<input
placeholder='Player name'
onFocus={(e)=>{e.target.placeholder=''}}
type="text"
id="name"
name="name" />
</div>
<div>
<input type='submit' />
</div>
</form>
</div>
</div>
);
}
And I got this in the console:
So how exactly do I extract the two inputs from the form?
In addition, is it possible that I can call another component and pass data as props to handle the submitted data so that the code is cleaner?
You should have a state to store your inputs:
const [formData, setFormData] = useState({ key: "", name: "" });
Then you need a function that gets called onChange of your input fields to update your state:
const onChange = (event) => {
setFormData({ ...formData, [event.target.name]: event.target.value });
};
And you need to pass that function to your input onChange property:
<input
placeholder="Your API key"
onFocus={(e) => {
e.target.placeholder = "";
}}
type="text"
name="key"
value={formData.key}
onChange={onChange}
/>
Then you can access the state in your handleSubmit:
function handlesubmit(e) {
console.log(formData);
e.preventDefault();
}

Reactjs: How to clear text field after submission

I have a signup page which has 4 input text fields which changes the currentState of each field from an empty string to whatever I inputted. After signing up it logs each of the following 4 fields input in a database with a post request. How can I clear each field after clicking on the sign up button. Basically I just want the page to clear after clicking. I have attempted to set the state of the 4 variables back to an empty string at the end of my promise chain but nothing changes still.
import React,{useState} from 'react';
import style from './Signup.css';
import Axios from 'axios';
function Signup() {
const [firstReg, setFirstNameReg] = useState('')
const [lastReg, setLastNameReg] = useState('')
const [emailReg, setEmailReg] = useState('')
const [passReg, setPassReg] = useState('')
const register = () => {
Axios.post('http://localhost:3001/register', {
first_name: firstReg,
last_name: lastReg,
email: emailReg,
password: passReg,
}).then((response)=> {
console.log(response);
setFirstNameReg('')
});
};
return (
<div className="Signup">
<div className='Sign'>
<div class="photo"> Create an account</div>
<div class ='searche'>
<div className="searchInputse">
<input type="text" onChange={(e)=> {setFirstNameReg(e.target.value)}} placeholder={'First name'} />
<div className="searchIcone"></div>
</div>
<div className="dataResult"></div>
</div>
<div class ='searche'>
<div className="searchInputse">
<input type="text" onChange={(e)=> {setLastNameReg(e.target.value)}} placeholder={'Last name'}/>
<div className="searchIcone"></div>
</div>
<div className="dataResult"></div>
</div>
<div class ='searche'>
<div className="searchInputse">
<input type="text" onChange={(e)=> {setEmailReg(e.target.value)}} placeholder={'Email'}/>
<div className="searchIcone"></div>
</div>
<div className="dataResult"></div>
</div>
<div class ='searche'>
<div className="searchInputse">
<input type="text" onChange={(e)=> {setPassReg(e.target.value)}} placeholder={'Password'}/>
<div className="searchIcone"></div>
</div>
<div className="dataResult"></div>
</div>
<button className='searchee' onClick={register}>
Sign Up
</button>
</div>
</div>
);
}
export default Signup;
A few things you should be aware of.
1st. You want to keep your data in an object for easy management and code reduction like so:
Define the initial object outside of your component;
let initialValues = {
'first_name': '',
'last_name': '',
'email': '',
}
And inside your component define state with the initialValues variable as the state default.
const [data, setData] = useState(initialValues);
And then, in your JSX you can connect the values with the object keys like so:
<input type="text" name="first_name" value={data.first_name} />
<input type="text" name="last_name" value={data.last_name} />
<input type="text" name="email" value={data.email} />
You can also then add an onChange handler to that input like so:
note: name must match the key inside of the initalValues object.
<input type="text" name="first_name" value={data.first_name} onChange={handleChange} />
<input type="text" name="last_name" value={data.last_name} onChange={handleChange} />
<input type="text" name="email" value={data.email} onChange={handleChange} />
handleChange basic function can look like this:
const onChange = (e) => {
setData({...data, [e.target.name]: e.target.value})
}
Essentially all you're doing is typing inside the input field, onChange detects a change on each key press, and fires off the handleChange function, that function makes a copy of the current state of data then looks at the e.target.name which could be first_name and sets it to e.target.value which is anything you type.
That way, all you need to pass to axios is the data object.
I hope this helps, let me know if you have any other questions.
Happy coding!
Hi try to replace your register button with this :
<button className='searchee' onClick={()=>{register();setFirstNameReg('');setLastNameReg('');setEmailReg('');setPassReg('')}}>
Sign Up
</button>

Form data binding with repeated forms in React

Parent Component
I have a parent component Users with the following snippet:
addUser(index, user) {
var users = this.state.users
var existingUser = users[index]
if (existingUser !== undefined) {
this.updateUser(index, user)
} else {
users.push(user)
this.setState({
users : users
})
}
}
updateUser(index, itemAttributes) {
this.setState({
travellers: [
...this.state.users.slice(0,index),
Object.assign({}, this.state.users[index], itemAttributes),
...this.state.users.slice(index+1)
]
});
}
The updateUser functionality has been taken from React: Updating state when state is an array of objects
And in JSX I have the following snippet:
...
<Form onSubmit={this._handleFormSubmit.bind(this)}>
<UserDetails index={0} callback = {this.addUser.bind(this)}/>
<UserDetails index={1} callback = {this.addUser.bind(this)}/>
<input type="submit" className="btn btn-primary mb-4" value="Continue"/>
</Form>
...
Child Component
Then in the child component UserDetails I have:
handleChange(event) {
event.preventDefault();
let formValues = this.state.formValues;
let name = event.target.name;
let value = event.target.value;
formValues[name] = value;
this.setState({formValues})
this.props.callback(this.props.index, this.state.formValues)
}
And in JSX:
<div className="row">
<div className="col-md-4">
<FormGroup>
<Label>First Name</Label>
<Input type="text" name="firstName" placeholder="First Name" value={this.state.formValues["firstName"]} onChange={this.handleChange.bind(this)} />
</FormGroup>
</div>
<div className="col-md-4">
<FormGroup>
<Label>Last Name</Label>
<Input type="text" name="lastName" placeholder="Last Name" value={this.state.formValues["lastName"]} onChange={this.handleChange.bind(this)} />
</FormGroup>
</div>
</div>
Now I can see two forms, each with a First Name and a Last Name fields. Now the problem is when I enter the First Name for the first user, the First Name for the second user is also automatically set to that of the first user. Thus, I cannot enter separate names for the two users. How can I solve this issue?
I see that you are mutating the state directly by using
let formValues = this.state.formValues;
formValues[name] = value;
One way to alleviate this issue is to spread the formValues before assigning
let formValues = {...this.state.formValues};
or you can use Immer

React updating the state value in a wrong place

I am trying to implement a simple form validation in React where the length of the name should be more than 1 char long, length of country should be more than 2 char long along with the password. However, the password and the country are getting validated properly. But, the name field isn't getting properly validated. Firstly, it's allowing to submit the name if it's just 1 char long and instead is showing the error in the country's span tag. Also, I am not sure how to implement the logic for email validation. Here is my code:
import React, { Component } from "react";
export default class SignUp extends Component {
constructor(){
super();
this.state={
name:'',
country:'',
email:'',
pass:'',
formErrors:{
nameError:'',
countryError:'',
emailError:'',
passwordError:''
}
}
this.handleChange=this.handleChange.bind(this);
this.handleValidate=this.handleValidate.bind(this);
this.handleSubmit=this.handleSubmit.bind(this);
}
handleChange =(e) =>{
let name=e.target.name;
let value=e.target.value;
this.setState({
[name]:value
})
}
handleValidate= () =>{
let { name,country,email,pass} =this.state;
let nameError, countryError, emailError, passError;
if(!name)
nameError="Missing name"
if(name && name.length<2)
countryError="Length of name should be more than 1 character"
if(!country)
countryError="Missing country"
if(country && country.length<3)
countryError="Length of country should be more than 2 characters"
/* if(!email)
emailError="Email can't be empty"
let lastAtPosi=email.lastIndexOf('#');
let lastDotPosi=email.lastIndexOf('.');
console.log("last # posti"+lastAtPosi);
console.log("Last . posi"+lastDotPosi);
*/
if(!pass)
passError="Password can't be empty"
if(pass && pass.length<6)
passError="Password must be more than 6 characters long"
this.setState({
formErrors:{
nameError:nameError,
countryError:countryError,
// emailError:emailError,
passwordError:passError
}
})
console.log("name "+nameError);
}
handleSubmit= (e) =>{
e.preventDefault();
this.handleValidate();
}
render() {
const { name, country, email, pass, formErrors } = this.state;
return (
<div>
<form>
<h3>Sign Up</h3>
<div className="form-group">
<label>Name</label>
<input type="text" onChange={this.handleChange}name="name"value={name} className="form-control" placeholder="Enter name" />
{formErrors.nameError? <span variant="danger">{formErrors.nameError}</span>:'valid'}
</div>
<div className="form-group">
<label>Country</label>
<input type="text" onChange={this.handleChange}name="country"value={country} className="form-control" placeholder="Enter country" />
{formErrors.countryError? <span variant="danger">{formErrors.countryError}</span>:'valid'}
</div>
<div className="form-group">
<label>Email address</label>
<input type="email" onChange={this.handleChange}name="email"value={email} className="form-control" placeholder="Enter email" />
{formErrors.emailError?<span variant="danger">{formErrors.emailError}</span>:'valid'}
</div>
<div className="form-group">
<label>Password</label>
<input type="password" onChange={this.handleChange}name="pass" value={pass} className="form-control" placeholder="Enter password" />
{formErrors.passwordError?<span variant="danger">{formErrors.passwordError}</span>:'valid'}
</div>
<button onClick={this.handleSubmit}type="submit" className="btn btn-primary btn-block">Sign Up</button>
</form>
</div>
);
}
}
Sandbox linkenter link description here
In your handleValidate, you assign an error to the wrong error variable:
if(name && name.length<2)
countryError="Length of name should be more than 1 character"
It should be:
if(name && name.length<2)
nameError="Length of name should be more than 1 character"

Async/await function is not working as expected

I'm new to using async/await and from my understanding, I can declare the function as an asynchronous function and then use await inside of that function.
What I would like for my code to do is to run document.getElementById('PrePayeezyForm').submit() only after the updateNewInvoice function has completed. UpdateNewInvoice function is setting data to my Redux store and I have a form that is referring to the data from the store.
The issue is, the last line is running so quickly that the form is referring to empty data in the store before it is set. If I use a setTimeout, it works but I don't want to have to do that. Thanks for the help.
import styles from './styles.module.scss'
const FormPayeezy = ({
payeezyArray,
removeInvoiceModal,
updateNewInvoice,
updatePO,
customer
}) => {
async function updateNewInvoices(event) {
event.preventDefault()
//save amount to redux and generate form values
let amount = event.target.x_amount.value
let customer = event.target.customer.value
await updateNewInvoice(amount, customer)
document.getElementById('PrePayeezyForm').submit();
}
function updatePOs(event) {
//save PO to redux
updatePO(event.target.value)
}
function hideModal(event) {
event.preventDefault()
removeInvoiceModal()
}
return (
<form id="PrePayeezyForm" className={styles.addInvoiceForm} method="post" action="https://demo.globalgatewaye4.firstdata.com/payment" onSubmit={updateNewInvoices}>
<input name="x_login" value={payeezyArray.login} type="hidden" />
<input name="x_invoice_num" value={payeezyArray.payment_num} type="hidden" />
<input name="x_fp_sequence" value={payeezyArray.sequence} type="hidden" />
<input name="x_fp_timestamp" value={payeezyArray.timestamp} type="hidden" />
<input name="x_fp_hash" value={payeezyArray.hash} type="hidden" />
<input name="x_show_form" value="PAYMENT_FORM" type="hidden" />
<input name="x_relay_response" value="TRUE" type="hidden" />
<label>Payment Description</label>
<input type="text" required name="loadNum" id="loadNum" onBlur={updatePOs} />
<label>Payment Amount</label>
<input type="text" required name="x_amount" id="x_amount" />
<input required name="customer" id="customer" value={customer} type="hidden" />
{payeezyArray.items}
<button className={styles.buttonAdd} type="submit"
>Pay Invoice</button>
<button className={styles.buttonCancel}
onClick={hideModal}
>Cancel</button>
</form>
)
}
export default FormPayeezy
//////////////////////////////////////////
updateNewInvoice = async (amount, customerid) => {
const { updatePayeezyCustomer, updatePayeezyAmount } = this.props
updatePayeezyAmount(amount)
updatePayeezyCustomer(customerid)
let loadid = this.props.payeezyArray.PO
let note = `New Invoice for PO #: ${loadid}`
let paymentInfo = {
'other': [
{
customerid,
note,
amount: Number(amount)
}
]
}
this.props.getPaymentResponse(paymentInfo, (id) => {
this.props.updatePayeezyPaymentNum(id)
})
let timestamp = Math.floor(Date.now() / 1000)
this.props.updatePayeezyTimestamp(timestamp)
let hash = createPayeezyHash(this.props.payeezyArray, timestamp, amount)
this.props.updatePayeezyHash(hash)
let value = `${this.props.payeezyArray.PO}<|><|>PO ${this.props.payeezyArray.PO}<|>1<|>${amount}<|>N`
let content = <input name="x_line_item" value={value} type="hidden"></input>
this.props.updatePayeezyItems(content)
}

Resources