As seen in the title, I need a form validation in accordance below code. I have tried to validate many times with nodemailer method before and it was working validation. Now I changed my method due to some issues therefore I try another method but I cant not implement that. Can anyone help me, please?
Here is my new contact form and its function.
const Form = () => {
function sendEmail(e) {
e.preventDefault();
emailjs
.sendForm(
'servxxxxxxxxxu',
'tempxxxxxxxxxxxxa',
e.target,
'userxxxxxxxxxxxxxxxxxxxx'
)
.then((res) => {
console.log(res);
})
.catch((err) => console.log(err));
}
return (
<div className="Contact">
<div className="wrapper">
<h1>Contact Form</h1>
<form onSubmit={sendEmail}>
<input
className="input-field"
type="text"
name="name"
placeholder="Name"
/>
<input
className="input-field"
type="text"
name="user_email"
placeholder="E-Mail"
/>
<textarea name="message" rows="4" placeholder="Message" />
<input type="submit" value="Send" />
</form>
</div>
</div>
);
};
export default Form;
This is my old validation, may be helpful to you.
const initialState = {
name: '',
subject: '',
email: '',
message: '',
sent: false,
nameError: '',
subjectError: '',
emailError: '',
messageError: '',
};
export default class Validation extends React.Component {
state = initialState;
handleName = (e) => {
this.setState({
name: e.target.value,
});
};
handleSubject = (e) => {
this.setState({
subject: e.target.value,
});
};
handleEmail = (e) => {
this.setState({
email: e.target.value,
});
};
handleMessage = (e) => {
this.setState({
message: e.target.value,
});
};
validate = () => {
let nameError = '';
let subjectError = '';
let emailError = '';
let messageError = '';
if (!this.state.name) {
nameError = 'Name cannot be blank!';
}
if (!this.state.subject) {
subjectError = 'Subject cannot be blank!';
}
if (this.state.message.length < 5) {
messageError = 'Message cannot be less 5 character!';
}
if (!this.state.email) {
emailError = 'E-mail cannot be blank!';
} else if (typeof this.state.email !== 'undefined') {
var mailformat = /^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if (!mailformat.test(this.state.email)) {
emailError = 'Incorrect e-Mail!';
}
}
if (emailError || nameError || subjectError || messageError) {
this.setState({ emailError, nameError, subjectError, messageError });
return false;
}
return true;
};
handleSubmit = (e) => {
e.preventDefault();
const isValid = this.validate();
if (isValid) {
console.log(this.state);
this.sendingMail();
this.setState(initialState);
}
};
sendingMail = () => {
let data = {
name: this.state.name,
subject: this.state.subject,
email: this.state.email,
message: this.state.message,
};
axios
.post('http://127.0.0.1:3001/api/form', data)
.then((res) => {
this.setState(
{
sent: true,
},
this.resetForm()
);
})
.catch(() => {
console.log('message not sent');
});
};
resetForm = () => {
this.setState({
name: '',
subject: '',
email: '',
message: '',
});
setTimeout(() => {
this.setState({
sent: false,
});
}, 3000);
};
}
you can merge all handle methods into 1
state = initialState;
handleInput = (e , stateName) => {
this.setState({ [`${stateName}`]: e.target.value})
};
with this jsx
<input type="text" placeholder="name" onChange={(e)=>{this.handleInput('name' ,e)}}
validation
var States = [ this.state.name, this.state.subject , this.state.email , this.state.message]
States.forEach((stateKey)=>{
if (!stateKey) this.setState({Error: `${stateKey} could not be blank`})
})
if (this.state.message.length < 5)this.setState({Error:'Message cannot be less 5 character!})
if (this.state.Error) return false;
return true
Related
Why I am not able to see validation alert clicking on the done button when everything is empty once form open even validation checks are proper ?
Basically form opens i don't type anything and click on done button so all validation checks should work and show text 'Required.Please enter your given name.' but it is not showing ?
Where is the issue which causes the state to be blank at the end
const addSecondaryContact = inject('apptContacts')(observer((props) => {
const {
i18n, nbnContact, apptContacts, backButtonContent,
} = props;
const { updatePrimaryContact } = apptContacts;
const CMS = i18n.appointmentManager.editAppointmentContact;
const [state, setState] = useState({
data: {
firstName: '',
lastName: '',
number: '',
},
firstNameValid: '',
lastNameValid: '',
numberValid: '',
});
const validFirstName = () => {
console.log(state.data.firstName);
if (!state.data.firstName) {
console.log('frstname1');
return 'Required.Please enter your given name.';
}
if (!/^[A-Za-z]+$/.test(state.data.firstName)) {
console.log('frstname2');
return 'Invalid entry.Please use letters only.';
} if (state.data.firstName.length === 1) {
console.log('frstname3');
return 'Invalid entry.More than one character is required';
}
console.log('&&&&');
return '';
};
const validLastName = () => {
console.log('988');
if (!state.data.lastName) { console.log('lastname'); return 'Required.Please enter your given name.'; }
if (!/^[A-Za-z]+$/.test(state.data.lastName)) {
return 'Invalid entry.Please use letters only.';
} if (state.data.lastName.length === 1) {
return 'Invalid entry.More than one character is required';
}
return '';
};
const validNumber = async () => {
console.log('777');
if (!state.data.number) { return 'Required.Please enter your mobile number.'; }
if (state.data.number.substr(0, 2) !== '04') {
return 'Invalid entry.Please enter your 10-digit mobile number starting with 04.';
} if (state.data.number.length !== 10) {
return 'Invalid entry.Please enter your 10-digit mobile number starting with 04.';
} if (state.data.number.length === 1) {
return 'Invalid entry.More than one number is required';
}
return '';
};
const valid = async () => {
console.log('milan');
setState({
...state,
firstNameValid: validFirstName(),
lastNameValid: validLastName(),
numberValid: validNumber(),
});
console.log(state.firstNameValid);
console.log(state.lastNameValid);
console.log(state.numberValid);
};
const handleTextareaChange = (event) => {
console.log('%%%');
const { data } = state;
data[event.target.name] = event.target.value;
setState({
...state,
data,
});
valid();
};
const saveButton = async () => {
console.log(state);
await valid();
if (valid()) {
console.log(state.firstNameValid);
console.log(state.lastNameValid);
console.log(state.numberValid);
if (!state.firstNameValid && !state.lastNameValid && !state.numberValid) {
const personName = `${state.data.firstName} ${state.data.lastName}`;
const primaryContact = {
name: personName,
phoneNumber: state.data.number,
// updatePrimaryContact(primaryContact)
};
// updatePrimaryContact(primaryContact)
backButtonContent();
}
}
};
return (
<div>
<VerticalSpacing size={ABLE_SPACING_SIZE.spacing4x} />
<h1 tabIndex="-1" className="HeadingB mt-sheet-heading">
{CMS.heading2}
</h1>
<VerticalSpacing size={ABLE_SPACING_SIZE.spacing3x} />
<TextField id="givenName" name="firstName" label={CMS.name} onChange={handleTextareaChange} value={state.data.firstName} />
{state.firstNameValid && (
<Alert variant="error" inline>
<p>
{state.firstNameValid}
</p>
</Alert>
)}
<VerticalSpacing size={ABLE_SPACING_SIZE.spacing3x} />
<TextField id="familyName" name="lastName" label={CMS.familyName} onChange={handleTextareaChange} value={state.data.lastName} />
{state.lastNameValid && (
<Alert variant="error" inline>
<p>
{state.lastNameValid}
</p>
</Alert>
)}
<VerticalSpacing size={ABLE_SPACING_SIZE.spacing3x} />
<TextField id="mobileNumber" name="number" label={CMS.mobile} onChange={handleTextareaChange} value={state.data.number} />
{state.numberValid && (
<Alert variant="error" inline>
<p>
{state.numberValid}
</p>
</Alert>
)}
<VerticalSpacing size={ABLE_SPACING_SIZE.spacing4x} />
<ActionButton className={styles.saveCta} variant="HighEmphasis" label={CMS.saveCTA} onClick={() => saveButton()} />
</div>
);
}));
export default addSecondaryContact;
You had two main issues:
you state update is not proper - you set state on multiple occasions
you had async in your validNumber method - which causes blank output
Here is the code i modify from your code - maybe it can help you. I removed extra components in order to remove dependencies and used only plain html.
Demo: https://codesandbox.io/s/upbeat-feynman-w3odj?file=/App.js
import "./styles.css";
import React from "react";
export default function App() {
const [state, setState] = React.useState({
data: {
firstName: "",
lastName: "",
number: ""
},
firstNameValid: "",
lastNameValid: "",
numberValid: ""
});
const validFirstName = () => {
console.log(state.data.firstName);
let result = "";
if (!state.data.firstName) {
console.log("frstname1");
result = "Required.Please enter your given name.";
}
if (!/^[A-Za-z]+$/.test(state.data.firstName)) {
console.log("frstname2");
result = "Invalid entry.Please use letters only.";
}
if (state.data.firstName.length === 1) {
console.log("frstname3");
result = "Invalid entry.More than one character is required";
}
console.log("&&&&");
return result;
};
const validLastName = () => {
console.log("988");
if (!state.data.lastName) {
console.log("lastname");
return "Required.Please enter your given name.";
}
if (!/^[A-Za-z]+$/.test(state.data.lastName)) {
return "Invalid entry.Please use letters only.";
}
if (state.data.lastName.length === 1) {
return "Invalid entry.More than one character is required";
}
return "";
};
const validNumber = () => {
console.log("777");
if (!state.data.number) {
return "Required.Please enter your mobile number.";
}
if (state.data.number.substr(0, 2) !== "04") {
return "Invalid entry.Please enter your 10-digit mobile number starting with 04.";
}
if (state.data.number.length !== 10) {
return "Invalid entry.Please enter your 10-digit mobile number starting with 04.";
}
if (state.data.number.length === 1) {
return "Invalid entry.More than one number is required";
}
return "";
};
const valid = async () => {
console.log("milan");
setState({
...state,
firstNameValid: validFirstName(),
lastNameValid: validLastName(),
numberValid: validNumber()
});
console.log(state.firstNameValid);
console.log(state.lastNameValid);
console.log(state.numberValid);
};
const handleTextareaChange = (event) => {
let validRes = "";
let key = "";
if (event.target.name === "firstName") {
validRes = validFirstName();
key = "firstNameValid";
}
if (event.target.name === "lastName") {
validRes = validLastName();
key = "firstNameValid";
}
if (event.target.name === "number") {
validRes = validNumber();
key = "numberValid";
}
console.log("234", validRes);
setState({
...state,
data: { ...state.data, [event.target.name]: event.target.value },
// [key]:
firstNameValid: validFirstName(),
lastNameValid: validLastName(),
numberValid: validNumber()
});
// valid();
};
const saveButton = async () => {
console.log(state);
await valid();
if (valid()) {
console.log(state.firstNameValid);
console.log(state.lastNameValid);
console.log(state.numberValid);
}
};
return (
<div>
<h1 tabIndex="-1" className="HeadingB mt-sheet-heading">
'CMS.heading2'
</h1>
<input
type="text"
id="givenName"
name="firstName"
label="CMS.name"
onChange={handleTextareaChange}
value={state.data.firstName}
/>
{state.firstNameValid && <p>{state.firstNameValid}</p>}
<input
type="text"
id="familyName"
name="lastName"
label="CMS.familyName"
onChange={handleTextareaChange}
value={state.data.lastName}
/>
{state.lastNameValid && <p>{state.lastNameValid}</p>}
<input
type="text"
id="mobileNumber"
name="number"
label="CMS.mobile"
onChange={handleTextareaChange}
value={state.data.number}
/>
{state.numberValid && <p>{state.numberValid}</p>}
<button
variant="HighEmphasis"
label="CMS.saveCTA"
onClick={() => saveButton()}
/>
</div>
);
}
I can't figure it out, why am I getting the error 'TypeError: can't access property "trim", action.val is undefined' after I tried to set the PassDispach on ValidateEmailHandler (which is used to trigger the unblur of the pass input) ? It seems to work on validateEmailHandler. I have tried setting the initial value of PassDefaultState to a string and this also throws me an error
const emailReducer = (state, action) => {
if (action.type === "USER_INPUT") {
return { value: action.val, isValid: action.val.includes("#") };
}
if (action.type === "INPUT_BLUR") {
return { value: state.value, isValid: state.value.includes("#") };
}
return { value: "", isValid: false };
};
const passReducer = (state, action) => {
if ((action.type = "PASS_INPUT")) {
return {
...state,
value: action.val,
isValid: action.val.trim().length > 6,
};
}
if ((action.type = "PASS_BLUR")) {
//this is where the error happens
return {
...state,
};
}
return { value: "", isValid: false };
};
const PassDefaultState = {
value: "",
isValid: null,
};
const MailDefaultState = {
value: "",
isValid: null,
};
const Login = (props) => {
// ! Email STATE ----------------------
const [emailState, dispatchEmail] = useReducer(emailReducer, MailDefaultState);
// ! PASSWORD STATE ----------------------
const [passState, passDispach] = useReducer(passReducer, PassDefaultState);
const { isValid: passIsValid } = passState;
const { isValid: mailIsValid } = emailState;
useEffect(() => {
const identifier = setTimeout(() => {
console.log("Checking form validity!");
setFormIsValid(mailIsValid && passIsValid);
}, 500);
return () => {
console.log("CLEANUP");
clearTimeout(identifier);
};
}, [passIsValid, mailIsValid]);
const emailChangeHandler = (event) => {
dispatchEmail({ type: "USER_INPUT", val: event.target.value });
};
const passwordChangeHandler = (event) => {
passDispach({ type: "PASS_INPUT", val: event.target.value });
setFormIsValid(emailState.isValid && passState.isValid);
};
const validateEmailHandler = () => {
dispatchEmail({ type: "INPUT_BLUR" });
};
const validatePasswordhandler = () => {
passDispach({ type: "PASS_BLUR" });
};
const submitHandler = (event) => {
event.preventDefault();
props.onLogin(emailState.value, passState.value);
};
return (
<Card className={classes.login}>
<form onSubmit={submitHandler}>
<div
className={`${classes.control} ${
emailState.isValid === false ? classes.invalid : ""
}`}
>
<label htmlFor="email">E-Mail</label>
<input
type="email"
id="email"
value={emailState.value}
onChange={emailChangeHandler}
onBlur={validateEmailHandler}
/>
</div>
<div
className={`${classes.control} ${
passState.isValid === false ? classes.invalid : ""
}`}
>
<label htmlFor="password">Password</label>
<input
type="password"
id="password"
value={passState.value}
onChange={passwordChangeHandler}
onBlur={validatePasswordhandler}
/>
</div>
<div className={classes.actions}>
<Button type="submit" className={classes.btn} disabled={!formIsValid}>
Login
</Button>
</div>
</form>
</Card>
);
};
export default Login;
if ((action.type = "PASS_INPUT")) {
Here you need to use === instead of =, the code you wrote is trying to assign a "PASS_INPUT" to action.type while you should chec the value
I get the error:email is badly formatted whenever I use the login form and the password doesn't get to firebase too
here's the error screenshot:
here
here's the code for the login form:
class LoginView extends React.Component {
constructor(props) {
super(props);
this.state = {
email : '',
password: '',
name:'',
phone:'',
fontsLoaded:false,
isLoading: false,
}
}
async componentDidMount(){
await Font.loadAsync({
'comfortaa':require('./assets/fonts/Comfortaa/static/Comfortaa-Bold.ttf'),
});
this.setState({fontsLoaded:true})
}
updateInputVal = (val, prop) => {
const state = this.state;
state[prop] = val;
this.setState(state);
}
registerUser = () => {
if(this.state.email === '' && this.state.password === '') {
Alert.alert('Enter details to signup!')
} else {
this.setState({
isLoading: true,
})
console.log(this.state.email);
firebase
.auth()
.createUserWithEmailAndPassword(this.state.email, this.state.password)
.then((res) => {
res.user.updateProfile({
name: this.state.name
})
console.log('User registered successfully!')
this.setState({
isLoading: false,
name: '',
email: '',
password: ''
})
this.props.navigation.navigate('Login')
})
.catch(error => {
this.setState({ errorMessage: error.message });
console.log(`Exception in registerUser:${error.message}`);
})
}
}
any idea to fix that error and the password error?
I am trying to enable/disable a form button based on if there are any characters in both the of the text input fields, but for some reason the state lengths are rendering an error with my conditional, despite when I log the state it shows up.
Error:
const isEnabled = this.state.subject.length > 0 && this.state.emails.length > 0;
//Uncaught TypeError: Cannot read property 'length' of undefined
Full Code:
import React from 'react';
export default class EmailAnnotationForm extends React.Component {
constructor(props) {
super(props);
this.state = {
csrf: '',
subject: '',
emails: '',
comment: ''
}
this.handleInputChange = this.handleInputChange.bind(this);
this.handleFormSubmit = this.handleFormSubmit.bind(this);
this.handleClearForm = this.handleClearForm.bind(this);
this.input = React.createRef();
}
componentDidMount() {
console.log(this.state.subject.length) // renders correct value => 0
this.setState({subject: this.props.title });
}
handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
handleClearForm() {
this.setState({
csrf: '',
subject: '',
emails: '',
comment: ''
})
}
handleFormSubmit(event) {
var emailSubject;
{
this.state.subject ? emailSubject = this.state.subject : emailSubject = this.props.title
}; //
const body = {
subject: emailSubject,
emails: this.state.emails,
comment: this.state.comment
};
event.preventDefault();
var route = `${API_ROOT}` + '/api/annotation/' + this.props.annotationId + '/share/email';
fetch(route,
{
method: 'POST',
body: JSON.stringify(body),
compress: false,
headers: {
'X-CSRF-Token': this.props.csrf,
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(res => {
return res.json();
})
.then(data => {
this.handleClearForm();
this.props.shareFlashMessage('success');
this.setState({'flash': 'success'});
this.props.closeShareModal(false);
})
.catch(err => {
console.log(err);
this.props.shareFlashMessage('error');
this.setState({'flash': 'error'});
});
}
render() {
var emailSubject;
{
this.state.subject
?
emailSubject = this.state.subject
:
emailSubject = this.props.title
};
console.log(this.state) // csrf: '', subject: undefined, emails: '', comment: ''
console.log(this.state.subject) // renders undefined
const isEnabled = this.state.subject.length > 0 && this.state.emails.length > 0; //Uncaught TypeError: Cannot read property 'length' of undefined
return (
<div className="annotation-footer__share-form-email">
<form action={"/api/annotation/" + this.props.annotationId + "/share/email"} method="post" onSubmit={this.handleFormSubmit} name="annotationEmailShare" id="share-email-form">
<div className="input-group annotation-footer__share-form-email-inputs">
<p><b>Subject:</b></p>
<input type="text" name="subject" className="form-control" defaultValue={this.props.title} onChange={this.handleInputChange}/><br />
</div>
<div className="input-group annotation-footer__share-form-email-inputs">
<p><b>Emails (Comma separate each email address):</b></p>
<input type="text" name="emails" className="form-control" onChange={this.handleInputChange}/><br />
</div>
<div className="input-group annotation-footer__share-form-email-inputs">
<p><b>Additional Comment (Optional):</b></p>
<textarea name="comment" rows="4" className="form-control" onChange={this.handleInputChange}></textarea><br />
</div>
<button type="submit" disabled={!isEnabled}>Send Email</button>
</form>
</div>
)
}
}
It seems this.props.title is undefined.
To solve the issue, put the check on this.props.title value, and update the state only if it has a valid value. Like this:
componentDidMount() {
if(this.props.title)
this.setState({ subject: this.props.title });
}
Suggestion:
Instead of updating subject with props value in didMount method, do it in constructor itself, Like this:
this.state = {
csrf: '',
subject: props.title || '',
emails: '',
comment: ''
}
I created this.state.data object. Now I need to put this.state.email and this.state.password into this.state.data.email2 and this.state.data.password2
I want to create local storage. To do that I need an object where I could store data. this.state.email and this.state.password are inputs.
class Register extends Component {
constructor(props){
super(props);
this.state = {
email: '',
password: '',
data: {
email2: '',
password2: '',
},
}
// This binding is necessary to make `this` work in the callback
this.handleEmailChange = this.handleEmailChange.bind(this);
this.handlePasswordChange = this.handlePasswordChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleEmailChange = (event) => {
this.setState({email: event.target.value});
}
handlePasswordChange = (event) => {
this.setState({password: event.target.value});
}
handleSubmit = (event) => {
event.preventDefault();
console.log(this.state.email);
console.log(this.state.password);
/*
Take values from input, ant put it into this state data array
*/
// Reset form;
this.setState({
email: '',
password: '',
})
}
When I activate handleSubmit method I expect to take this.state.email, and this.state.password. And put it into object this.state.data
Hope you need to pass this.state.email and this.state.password to this.state.data
You can do that in handleEmailChange and handlePasswordChange itself, and your using arrow functions, so don't need to bind this in constructor.
Check a code below:
class App extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
password: '',
data: {
email2: '',
password2: '',
},
}
}
handleEmailChange = (event) => {
this.setState({
email: event.target.value,
data: {
...this.state.data,
email2: event.target.value,
}
});
}
handlePasswordChange = (event) => {
this.setState({
password: event.target.value,
data: {
...this.state.data,
password2: event.target.value,
}
});
}
handleSubmit = (event) => {
event.preventDefault();
console.log(this.state.email);
console.log(this.state.password);
console.log('object data');
console.log(this.state.data);
/*
Take values from input, ant put it into this state data array
*/
// Reset form;
this.setState({
email: '',
password: '',
}, () => console.log(this.state))
}
render() {
return (
<div>
<input type="text" onChange={this.handleEmailChange} value={this.state.email} />
<br/><br/>
<input type="text" onChange={this.handlePasswordChange} value={this.state.password} />
<br/><br/>
<button type="button" onClick={this.handleSubmit}>Submit</button>
</div>
);
}
}
Working demo
and don't need to write separate events for similar functionalities, Check the demo once, you can do it like below:
<input type="text" data-field = "email" onChange={this.handleChange} value={this.state.email} />
<input type="text" data-field = "password" onChange={this.handleChange} value={this.state.password} />
and in handleChange
handleChange = (event) => {
this.setState({
[event.target.getAttribute('data-field')]: event.target.value,
data: {
...this.state.data,
[`${event.target.getAttribute('data-field')}2`]: event.target.value,
}
});
}
Hope this helps.
Like this (assuming your setup supports spread operator ... )
handleEmailChange = event => {
this.setState({ email: event.target.value });
this.setState(prevState => ({ data: { ...prevState.data, email2: event.target.value } }));
};
handlePasswordChange = event => {
this.setState({ password: event.target.value });
this.setState(prevState => ({ data: { ...prevState.data, password2: event.target.value } }));
};
You can do like this
handleSubmit = (event) => {
event.preventDefault();
console.log(this.state.email);
console.log(this.state.password);
const {data} = this.state;
data.email2 = this.state.email;
data.password2 = this.state.password;
this.setState({ data });
// Reset form;
this.setState({
email: '',
password: '',
})
}
or without mutating the state (good practice)
this.setState(prevState => ({
data: {
...prevState.data,
[data.email2]: this.state.email
[data.password2]: this.state.password
},
}));