I'm new to react, and I've done a Form which I want to come up an alert when clicking the submit button. When I opened it on a browser through my local file it worked but when seeing on GitHub I don't get the same result, not sure why. I save it and push it to the repository.
Here it's how it looks https://joanaoli09.github.io/milestone/
Here is the code to the Form.js file:
import React from "react";
import "./Form.css";
export default class Form extends React.Component {
state = {
firstName: "",
lastName: "",
userName: "",
email: "",
password: ""
};
onSubmit = e => {
alert("Your information has been uploaded");
e.preventDefault();
this.props.onSubmit(this.state);
this.setState({
firstName: "",
lastName: "",
userName: "",
email: "",
password: ""
});
};
render() {
return (
<div className="formcontainer">
<form className="Form">
<p className="register">CREATE ACCOUNT</p>
<input
className="input"
name="firstName"
placeholder="First name"
value={this.state.firstName}
onChange={e => this.change(e)}
/>
<br />
<input
className="input"
name="lastName"
placeholder="Last name"
value={this.state.lastName}
onChange={e => this.change(e)}
/>
<br />
<input
className="input"
name="username"
placeholder="Username"
value={this.state.username}
onChange={e => this.change(e)}
/>
<br />
<input
className="input"
name="email"
placeholder="Email"
value={this.state.email}
onChange={e => this.change(e)}
/>
<br />
<input
className="input"
name="password"
type="password"
placeholder="Password"
value={this.state.password}
onChange={e => this.change(e)}
/>
<br />
<button className="submit" onClick={e => this.onSubmit(e)}>
Submit
</button>
</form>
</div>
);
}
}
If you inspect the Form.js file on that URL, you will see this:
onSubmit = e => {
e.preventDefault();
this.props.onSubmit(this.state);
this.setState({
firstName: "",
lastName: "",
userName: "",
email: "",
password: ""
});
};
So it looks like what you have deployed to that URL and what you have posted here is not the same. You might have pushed some new code to your repo, but if the changes are not appearing on that URL, you might have forgotten to deploy them again or the deploy pipeline might have failed for some reason.
The code here is missing some bits like the onChange callback, but adding them back it works just fine:
const App = () => {
const [state, setState] = React.useState({
firstName: '',
lastName: '',
username: '',
email: '',
password: '',
});
const handleSubmit = React.useCallback((e) => {
alert('Your information has been uploaded.');
e.preventDefault();
setState({
firstName: '',
lastName: '',
username: '',
email: '',
password: '',
});
}, []);
const handleChange = React.useCallback(({ target }) => {
setState((prevState) => ({ ...prevState, [target.name]: target.value }));
}, []);
return (
<div className="formcontainer">
<form className="Form">
<p className="register">CREATE ACCOUNT</p>
<input
className="input"
name="firstName"
placeholder="First name"
value={ state.firstName }
onChange={ handleChange }
/>
<input
className="input"
name="lastName"
placeholder="Last name"
value={ state.lastName }
onChange={ handleChange }
/>
<input
className="input"
name="username"
placeholder="Username"
value={ state.username }
onChange={ handleChange }
/>
<input
className="input"
name="email"
placeholder="Email"
value={ state.email }
onChange={ handleChange }
/>
<input
className="input"
name="password"
type="password"
placeholder="Password"
value={ state.password }
onChange={ handleChange }
/>
<button className="submit" onClick={ handleSubmit }>
Submit
</button>
</form>
</div>
);
}
ReactDOM.render(<App />, document.querySelector('#app'));
body {
font-family: monospace;
}
.input,
.submit {
display: block;
margin-bottom: 8px;
font-family: monospace;
padding: 8px;
background: white;
border: 2px solid black;
}
<script src="https://unpkg.com/react#16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom#16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>
I think there are some issues in your code here
<input
className="input"
name="username"
placeholder="Username"
value={this.state.username}
onChange={()=>this.change(e)}
/>
Here instead of name="username" it should be name="userName" because in
change = e => {
this.setState({
[e.target.name]: e.target.value //you are passing [e.target.name]
});};
And please make sure you always deploy the code again after making any changes in the repo by running npm run deploy
Related
Currently, i have this state with a formData.
Upon typing some text, instead to change the fullName.firstName. its making another property and just setting a single (as in single letter) value.
const [formData, setFormData] = useState({
fullName: {
firstName: "",
lastName: "",
},
email: "",
password: "",
confirmPassword: "",
});
This is how i set the formData.
const handleChange = (event) => {
const { value, name } = event.target;
console.log(name, value);
setFormData((prevFormData) => ({
...prevFormData,
[name]: value,
}));
};
This is my JSX, you may check the "name" attribute in input for some reference.
<div className="App">
<form onSubmit={onSubmit}>
<h1>Submit Form Nested Object UseState</h1>
<input
text="text"
placeholder="First Name"
name="firstName"
value={formData.fullName.firstName}
onChange={handleChange}
/>
<input
text="text"
placeholder="Last Name"
name="lastName"
value={formData.fullName.lastName}
onChange={handleChange}
/>
<input
text="email"
placeholder="email"
name="email"
value={formData.email}
onChange={handleChange}
/>
<input
text="password"
placeholder="password"
name="password"
value={formData.password}
onChange={handleChange}
/>
<input
text="password"
placeholder="confirm Password"
name="confirmPassword"
value={formData.confirmPassword}
onChange={handleChange}
/>
<button>Submit</button>
</form>
{JSON.stringify(formData, null, 2)}
</div>
Change the form names like so:
<form onSubmit={onSubmit}>
<h1>Submit Form Nested Object UseState</h1>
<input
placeholder="First Name"
name="fullName.firstName"
value={formData.fullName.firstName}
onChange={handleChange}
/>
<input
placeholder="Last Name"
name="fullName.lastName"
value={formData.fullName.lastName}
onChange={handleChange}
/>
<input
placeholder="email"
name="email"
value={formData.email}
onChange={handleChange}
/>
<input
placeholder="password"
name="password"
value={formData.password}
onChange={handleChange}
/>
<input
placeholder="confirm Password"
name="confirmPassword"
value={formData.confirmPassword}
onChange={handleChange}
/>
<button>Submit</button>
</form>
then change your handleChange function to this:
const handleChange = (event) => {
const { value } = event.target;
const [key,subkey] = event.target.name.split('.');
setFormData((prevFormData) => ({
...prevFormData,
[key]: subkey ? {
...prevFormData[key],
[subkey]: value,
} : value
}));
};
How can I prevent onSubmit from being triggered if the form is already submitting?
If I add something like if (isSubmitting) return, Formik will treat that as the Promise being resolved and set isSubmitting to false immediately (even if there is a previous Promise running).
import React from 'react';
import ReactDOM from 'react-dom';
import { Formik, Field, Form } from 'formik';
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const Example = () => (
<div>
<h1>Sign Up</h1>
<Formik
initialValues={{
firstName: '',
lastName: '',
email: '',
}}
onSubmit={async (values) => {
console.log("submitting!!")
await sleep(1000);
}}
>
{({ isSubmitting }) => (
<Form>
<label htmlFor="firstName">First Name</label>
<Field name="firstName" placeholder="Jane" />
<label htmlFor="lastName">Last Name</label>
<Field name="lastName" placeholder="Doe" />
<label htmlFor="email">Email</label>
<Field name="email" placeholder="jane#acme.com" type="email" />
<button type="submit">
Submit
</button>
</Form>
)}
</Formik>
</div>
);
ReactDOM.render(<Example />, document.getElementById('root'));
In this case, you could add disabled to button whenever isSubmitting is true. So that user cannot click if isSubmitting process is ongoing.
<Formik
initialValues={{
firstName: "",
lastName: "",
email: ""
}}
onSubmit={async (values) => {
console.log("submitting!!");
await sleep(1000);
}}
>
{({ isSubmitting }) => (
<Form>
<label htmlFor="firstName">First Name</label>
<Field name="firstName" placeholder="Jane" />
<label htmlFor="lastName">Last Name</label>
<Field name="lastName" placeholder="Doe" />
<label htmlFor="email">Email</label>
<Field name="email" placeholder="jane#acme.com" type="email" />
<button disabled={isSubmitting} type="submit">
Submit
</button>
</Form>
)}
</Formik>
Furthermore if you want to have more control onisSubmitting props, you could manipulate it with setSubmitting in the onSubmit process.
<Formik
initialValues={{
firstName: "",
lastName: "",
email: ""
}}
onSubmit={async (values, {setSubmitting}) => {
setSubmitting(true) // if you want more control
console.log("submitting!!");
await sleep(1000);
setSubmitting(false) // if you ant more control
}}
>
...
</Formik>
I am trying to create a payment system in my application.
I have a payment form(paymentForm.js) and it contains the payment information(cardnumber, cvv, expiry...). Is there any way that I can get these information on another component(checkoutPage.js)? Do you have any advice?
Below is my paymentForm.js:
export default class PaymentForm extends React.Component {
state = {
cvv: '',
expiry: '',
focus: '',
name: '',
number: '',
};
handleInputFocus = (e) => {
this.setState({ focus: e.target.name });
}
handleInputChange = (e) => {
const { name, value } = e.target;
this.setState({ [name]: value });
}
render() {
return (
<View>
<Cards id="PaymentForm"
cvc={this.state.cvc}
expiry={this.state.expiry}
focused={this.state.focus}
name={this.state.name}
number={this.state.number}
/>
<form style={{}}>
<input
type="tel"
name="number"
placeholder="Card Details"
maxLength="16"
preview='true'
onChange={this.handleInputChange}
onFocus={this.handleInputFocus}
/>
<br/>
<input
type="text"
name="name"
placeholder="Holder Name"
onChange={this.handleInputChange}
onFocus={this.handleInputFocus}
/>
<br/>
<input
type="tel"
name="expiry"
placeholder="Expiration"
maxLength="4"
onChange={this.handleInputChange}
onFocus={this.handleInputFocus}
/>
<br/>
<input
type="tel"
name="cvc"
placeholder="CVV"
maxLength="5"
onChange={this.handleInputChange}
onFocus={this.handleInputFocus}
/>
<br/>
<input
type="tel"
name="zipcode"
placeholder="ZIP Code"
maxLength="5"
onChange={this.handleInputChange}
onFocus={this.handleInputFocus}
/>
</form>
</View>
);
}
}
You should create a file CheckOut.js and give card information via props. There is also another way to do it by creating a class named 'Checkout' and creating static methods inside.
This is my jsx for the form
import React, { Component } from "react";
import { createUser } from "../HTTPRequests";
import PhoneInput from "react-phone-number-input";
class UserRegForm extends Component {
constructor(props) {
super(props);
this.state = {
email: "",
password: "",
secondPassword: "",
username: "",
phone: "",
current: 0
};
this.handleEmail = this.handleEmail.bind(this);
this.handlePassword = this.handlePassword.bind(this);
this.handleSecondPassword = this.handleSecondPassword.bind(this);
this.handleUsername = this.handleUsername.bind(this);
this.renderSecondPassword = this.renderSecondPassword.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
this.handlePhone = this.handlePhone.bind(this);
}
handleEmail(event) {
this.setState({ email: event.target.value });
}
handlePassword(event) {
this.setState({ password: event.target.value });
}
handleSecondPassword(event) {
this.setState({ secondPassword: event.target.value });
}
handleUsername(event) {
this.setState({ username: event.target.value });
}
handlePhone(phone) {
this.setState({ phone: phone.value });
}
renderSecondPassword() {
var classN;
if (
this.state.secondPassword.length === 0 ||
this.state.secondPassword === this.state.password
) {
classN = "form-control";
} else {
classN = "form-control is-invalid";
}
return (
<div className="form-group">
<label htmlFor="InputPassword2">Introduza novamente a Password</label>
<input
onKeyDown={this.handleKeyDown}
onChange={this.handleSecondPassword}
type="password"
className={classN}
id="InputPassword2"
/>
</div>
);
}
handleKeyDown(event) {
if (event.key === "Enter") {
this.handleSubmit();
}
}
handleSubmit() {
createUser(this.state.email, this.state.password, this.state.username).then(
function(r) {
console.log(r);
}
);
}
render() {
return (
<div className="position-relative m-4">
<form>
<div className="form-group">
<label htmlFor="exampleInputUsername">Nome Completo</label>
<input
onKeyDown={this.handleKeyDown}
onChange={this.handleUsername}
type="username"
className="form-control"
id="exampleInputUsername"
/>
</div>
<div className="form-group">
<label htmlFor="exampleInputEmail1">E-mail</label>
<input
onKeyDown={this.handleKeyDown}
onChange={this.handleEmail}
type="email"
className="form-control"
id="exampleInputEmail1"
aria-describedby="emailHelp"
/>
<small id="emailHelp" className="form-text text-muted">
Nunca partilharemos o seu e-mail com ninguém.
</small>
</div>
<PhoneInput
placeholder="Enter phone number"
value={this.state.phone}
onChange={phone => this.handlePhone({ phone })}
/>
<div className="form-group">
<label htmlFor="InputPassword1">Password</label>
<input
onKeyDown={this.handleKeyDown}
onChange={this.handlePassword}
type="password"
className="form-control"
id="InputPassword1"
/>
</div>
{this.renderSecondPassword()}
<button
type="button"
className="btn btn-primary"
onClick={this.handleSubmit}
>
Submit
</button>
</form>
</div>
);
}
}
export default UserRegForm;
And this is the result...
as you can see the flag just expands to the whole screen.
I have programming experience (C and java), but just started learning HTML and React... So i'm still a bit lost. do I have to wrap the phone number component in something so it behaves? According to documentation the flag should be to the left of the input and not below
Any help is very appreciated
As someone who just encountered the same issue as OP after an update, the fix was very simple:
import 'react-phone-number-input/style.css'
According to last version of the docs : https://github.com/catamphetamine/react-phone-number-input
I'm new to React and have run into a problem building a simple form component. There are four input fields and four matching onChange handlers. All of them are effectively identical:
handleEmailChange(event) {
this.setState({email: event.target.value});
}
handlePasswordChange(event) {
this.setState({password: event.target.value});
}
handleFirstNameChange(event) {
this.setState({firstName: event.target.value});
}
handleLastNameChange(event) {
this.setState({lastName: event.target.value});
}
render() {
return (
<div>
<label>Email: </label>
<input type="text" name="email" placeholder="Email" value={this.state.email} onChange={this.handleEmailChange} />
<label>Password: </label>
<input type="password" name="password" placeholder="Password" value={this.state.password} onChange={this.handlePasswordChange} />
<label>First name: </label>
<input type="text" name="firstName" placeholder="First name" value={this.state.firstName} onChange={this.handleFirstNameChange} />
<label>Last name: </label>
<input type="text" name="lastName" placeholder="Last name" value={this.state.lastName} onChange={this.handleLastNameChange} />
<input type="submit" value="Add User" onClick={this.handleSubmit} />
</div>
)
}
Three of these work just fine. The password handler, however, throws a TypeError exception "event.target is undefined" when the page tries to render. If I remove the handler and input element, the app renders. If I copy and paste one of the other handlers and inputs and change the relevant names, it still throws the exception. If I change the input type from "password" to "text" it still throws the exception. I cannot figure out why a seemingly identical piece of code is throwing this exception but every other piece of code like it works just fine.
In case it matters, the code for the entire component is
class AddUserForm extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
firstName: '',
lastName: ''
};
this.validate = this.validate.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleEmailChange = this.handleEmailChange.bind(this);
this.handlePasswordChange = this.handlePasswordChange(this);
this.handleFirstNameChange = this.handleFirstNameChange.bind(this);
this.handleLastNameChange = this.handleLastNameChange.bind(this);
}
validate(user) {
return (user.email && user.password && user.firstName && user.lastName);
}
handleSubmit(event) {
let newUser = {
email: this.state.email,
password: this.state.password,
firstName: this.state.firstName,
lastName: this.state.lastName
};
if (AddUserForm.validate(newUser)) {
fetch(`http://localhost:3001/admin/addUser`, {
method: 'post',
headers: new Headers({
'Content-Type': 'application/x-www-form-urlencoded',
}),
body: JSON.stringify(newUser)
})
.then( res => {
const copy = [newUser].concat(this.state.users);
this.setState({users: copy});
})
}
event.preventDefault();
}
handleEmailChange(event) {
this.setState({email: event.target.value});
}
handlePasswordChange(event) {
this.setState({password: event.target.value});
}
handleFirstNameChange(event) {
this.setState({firstName: event.target.value});
}
handleLastNameChange(event) {
this.setState({lastName: event.target.value});
}
render() {
return (
<div>
<label>Email: </label>
<input type="text" name="email" placeholder="Email" value={this.state.email} onChange={this.handleEmailChange} />
<label>Password: </label>
<input type="password" name="password" placeholder="Password" value={this.state.password} onChange={this.handlePasswordChange} />
<label>First name: </label>
<input type="text" name="firstName" placeholder="First name" value={this.state.firstName} onChange={this.handleFirstNameChange} />
<label>Last name: </label>
<input type="text" name="lastName" placeholder="Last name" value={this.state.lastName} onChange={this.handleLastNameChange} />
<input type="submit" value="Add User" onClick={this.handleSubmit} />
</div>
)
}
}
You are invoking handlePasswordChange in the constructor by writing handlePasswordChange(this). You want to bind it to this instead.
this.handlePasswordChange = this.handlePasswordChange.bind(this);