disable form submit button until user checks recaptcha checkbox - javascript

I'm trying to disable my form's submit button until the user clicks the Google Recaptcha checkbox 'I am not a robot'
Is there anyway to do this or do I need to download a React component specific to Google Recaptcha?
Here is my simple component that contains the Google Recaptcha:
const RecaptchaComponent = () => {
useEffect(() => {
// Add reCaptcha
const script = document.createElement("script");
script.src = "https://www.google.com/recaptcha/api.js"
document.body.appendChild(script);
}, [])
return (
<div
className="g-recaptcha"
data-sitekey="6LeS8_IdfdfLtQzwUgNV4545454lhvglswww14U"
></div>
)
};
And here is my form's onSubmit code:
const GameForm = () => (
<div className="app">
<Formik
initialValues={{
email: "",
name: "",
title: ""
}}
onSubmit={(values) => {
//new Promise(resolve => setTimeout(resolve, 500));
axios({
method: "POST",
url: "api/gameform",
data: JSON.stringify(values),
});
}}
>
{props => {
const {
values,
isSubmitting,
handleSubmit,
} = props;
return (
<form onSubmit={handleSubmit}>
<div>Your Game</div>
<label htmlFor="title">
Game Title:
</label>
<Field
id="title"
type="text"
values={values.title}
/>
<label htmlFor="name">
Name:
</label>
<Field
id="name"
type="text"
value={values.name}
/>
<label htmlFor="email">
Email:
</label>
<Field
id="email"
name="email"
type="email"
value={values.email}
/>
<div>
<ReCAPTCHA
sitekey="6LeS8_IUAAAAAhteegfgwwewqe223"
onChange={useCallback(() => setDisableSubmit(false))}
/>
</div>
<div>
<Button type="submit">
Submit
</Button>
</div>
</form>
);
}}
</Formik>
</div>
);

You don't need to use the react component, but it's easier.
export const MyForm = () => {
const [disableSubmit,setDisableSubmit] = useState(true);
return (
... rest of your form
<ReCAPTCHA
sitekey="6LeS8_IdfdfLtQzwUgNV4545454lhvglswww14U"
onChange={useCallback(() => setDisableSubmit(false))}
/>
<button type="submit" disabled={disableSubmit}>Submit</button>
)
}
EDIT:
One of my biggest pet peeves is seeing React tutorials where authors encourage devs to use functions that return JSX instead of just using functional components.
Formik's "children as a function" pattern is gross (react-router-dom does the same thing) - it should be a component:
const GameForm = () => {
return <Formik ...your props>{props => <YourForm {...props}/>}</Formik>
}
const YourForm = (props) => {
const [disableSubmit,setDisableSubmit] = useState(true);
... everything inside the child function in `GameForm`
}

Related

onValidated is not a function when trying to subscribe user to mailchimp

I am using "react-mailchimp-subscribe" to integrate with MailChimp and enable users to signup to a mailchimp mailing list upon completing an submitting my form.
However, I get the error:
Uncaught TypeError: onValidated is not a function
When I trigger the function that should submit the form info to MailChimp.
Here is a sample of my code:
import MailchimpSubscribe from "react-mailchimp-subscribe";
...
const CustomForm = ({
className,
topOuterDivider,
bottomOuterDivider,
topDivider,
bottomDivider,
hasBgColor,
invertColor,
split,
status,
message,
onValidated,
...props
}) => {
...
const [email, setEmail] = useState('');
const [fullName, setFullName] = useState('');
const handleSubmit = (e) => {
console.log('handlesubmit triggered')
e.preventDefault();
email &&
fullName &&
email.indexOf("#") > -1 &&
onValidated({
EMAIL: email,
MERGE1: fullName,
});
}
...
<form onSubmit={(e) => handleSubmit(e)}>
<h3>
{status === "success"
? "You have successfully joined the mailing list"
: "Join our mailing list by completing the form below"
}
</h3>
<div className="cta-action">
<Input
id="email"
type="email"
label="Subscribe"
labelHidden hasIcon="right"
placeholder="Your email address"
onChange={e => setEmail(e.target.value)}
value={email}
isRequired
>
</Input>
<Input
id="name"
type="text"
label="Subscribe"
labelHidden hasIcon="right"
placeholder="Your full name"
onChange={e => setFullName(e.target.value)}
value={fullName}
isRequired
>
</Input>
<Input
type="submit"
formValues={[email, fullName]}
/>
</div>
</form>
This is the parent component passing down props to the above:
import React from "react";
import MailchimpSubscribe from "react-mailchimp-subscribe";
const MailchimpFormContainer = props => {
const postURL = `https://*li$%.list-manage.com/subscribe/post?u=${process.env.REACT_APP_MAILCHIMP_U}$id=${process.env.REACT_APP_MAILCHIMP_ID}`;
return (
<div>
<MailchimpSubscribe
url={postURL}
render={({ subscribe, status, message }) => (
<CustomForm
status={status}
message={message}
onValidated={ formData => subscribe(formData) }
/>
)}
/>
</div>
);
};

where to call the Axios post request in reactjs

I have a form,thats data are saved in the state to be sent to the backend server.
i am handling the form with handleSubmit function and useEffect hook, where the handleSubmit prevents the form from being submitted unless it calls the validation function, in the useEffect I check if there are any errors using if condition and then console.log my data.
now I want to post the data hold in the state -the state is sent as a props to me- but I am confused whether to put the request in the HandleSubmit function or in the useEffect inside the body of the if condition.
import react, { Component, useState, useEffect } from 'react';
import {useNavigate } from 'react-router-dom';
import axios from 'axios';
import './sign.css';
const SignA = (props) => {
const navigate = useNavigate();
const [formErrors, setFormErrors] = useState({});
const [isSubmit, setIsSubmit] = useState(false);
const handleSubmit = (err) => {
err.preventDefault();
setFormErrors(validate(props.data));
setIsSubmit(true);
}
useEffect(() => {
console.log(Object.keys(formErrors).length);
if (Object.keys(formErrors).length === 0 && isSubmit) {
console.log('console the props data', props.data)
//here is where I think the post request should be put
if (isSubmit) {
return (navigate('/profileadmin'))
}
}
}, [formErrors])
const validate = (values) => {
const errors = {};
const regex = /^[^\s#]+#[^\s#]+\.[^\s#]{2,}$/i;
if (!values.firstname) {
errors.firstname = 'firstname is required!';
}
if (!values.lastname) {
errors.lastname = 'lastname is required!';
}
if (!values.mobile) {
errors.mobile = 'mobile is required!';
}
if (!values.email) {
errors.email = 'email is required!';
} else if (!regex.test(values.email)) {
errors.email = 'this is not a valid email format!'
}
return errors;
}
return (
<div className='signup'>
<form onSubmit={handleSubmit} >
<div className="container">
<h1>Sign Up</h1>
<div className="name">
<div>
<input
type="text"
placeholder="First name"
name="firstname"
id='firstName'
value={props.data.firstname}
onChange={props.change}
/>
</div>
<div>
<input
type="text"
placeholder="Last name"
name="lastname"
value={props.data.lastname}
onChange={props.change}
/>
</div>
</div>
<p className='errorMsg'>{formErrors.firstname}</p>
<p className='errorMsg'>{formErrors.lastname}</p>
<br />
<div>
<input
type="text"
placeholder="Business mobile number"
name="mobile"
value={props.data.mobile}
onChange={props.change}
/>
<p className='errorMsg'>{formErrors.mobile}</p>
<br />
<input
type="text"
placeholder="Email Adress"
name="email"
value={props.data.email}
onChange={props.change}
/>
<p className='errorMsg'>{formErrors.email}</p>
<br />
</div>
</div>
<br />
<div className="checkbox">
<label>
<input type="checkbox" className="check" />i’ve read and agree with <a href="url" >Terms of service</a>
</label>
</div>
<div className="clearfix">
<button type="submit" className="signupbtn">Sign Up</button>
</div>
</div>
</form >
</div >
)
}
export default SignA;
this is the request
axios.post('', props.data)
.then(res => console.log('post res', res))
.catch(error => {
console.error('There was an error in post request!', error);
});
You don't necessarily need useEffect here.
Here is how you can implement such thing:
Declare a state to hold form values:
const [formData, setFormData] = useState({})
Declare function to set the state:
const handleChange = (name, value) => {
setFormData({...formData, [name]: value})
}
Input onChange to capture:
// handleChange has two parameters
<input
type="text"
placeholder="First name"
name="firstname"
id='firstName'
value={props.data.firstname}
onChange={(event) => handleChange('firstName', event.target.value)}
/>
function for calling post axios post request
const handleSubmit = () => {
//check for validations code here
// if validations are right then post request here
// this will give you all the fields like firstName: "", lastName: ""
let requestBody = {
...formData
}
axios.post("url", requestBody).then((res)=> {
//your code here
})
}

Set state using onChange using hook

I want to get the value when I change it with onChange and created a name and contact number by using the value and setContacts, this app does not cause error but it does not work, Where is the problem? Thanks.
Each new contact in an object has an id, a name and a phone number
const AddUSer = () => {
const {contacts, setcontacts}=useState([]);
const { userName, setUSerName } = useState("");
const { userPhone, setUserPhone } = useState("");
const setName = (e) => {
const value = e.target.value;
return setUSerName(value);
};
const setPhone = (e) => {
const value = e.target.value;
return setUserPhone(value);
};
const handleNewcontact = () => {
const allcontacts = [...contacts];
const newContact = {
id: Math.floor(Math.random() * 1000),
fullName: userName,
phone: userPhone,
};
allcontacts.push(newContact);
setcontacts(allcontacts);
setUSerName("");
setUserPhone("");
}
};
return (
<div className="container">
<form>
<label>Name</label>
<input className="form-control" onChange={(e) => setName} />
<label>Phone</label>
<input className="form-control" onChange={(e) => setPhone} />
<button
onClick={handleNewcontact}
className="btn btn-primary mt-3 mb-4"
>
Save
</button>
</form>
</div>
);
};
export default AddUSer;
You are not passing the event to the function. You can either do
onChange={(e) => setName(e)}
onChange={(e) => setPhone(e)}
but better:
onChange={setName}
onChange={setPhone}
try this. the values are consoled when the user clicks the submit button.
const AddUSer = () => {
const [contact, setContact] = useState({id: '', userName:'', userPhone:''});
function handleNewContact(event) {
setContact({
...contact, id: Math.floor(Math.random() * 1000),
[event.target.name]: event.target.value
});
}
function handleSubmit(event) {
event.preventDefault();
console.log(contact);
}
return (
<div className="container">
<form>
<label>Name</label>
<input className="form-control" name='userName'
onChange={handleNewContact} />
<label>Phone</label>
<input className="form-control" name='userPhone'
onChange={handleNewContact} />
<button
onClick={handleSubmit}
className="btn btn-primary mt-3 mb-4"
>
Save
</button>
</form>
</div>
);
};
export default AddUSer;

Why is this deleting all of my items in the array at once? React

I'm trying to build a CV builder which the user can input information such as the company, date, title, location and it gets saved inside an array when the user presses the save button. Then, that array is rendered in HTML form with a remove button.
I want that remove button to only delete one item of an array. For example, if we create two companies I've worked on it would create a remove button for both of them
I want that when we click the remove button once, not all the items of the array gets deleted which is what my code is currently doing. I can't figure out a logic to perform this and I've only tried this filter method but it deletes all of the items...
import React, { useState } from "react";
import '../styles/style.css'
const Experience = (props) => {
const [toggle, setToggle] = useState(false);
const [input, setInput] = useState({title: "", company: "", date: "", location: "", description: ""})
const [result, setResult] = useState([])
const togglePopup = () => {
setToggle(!toggle);
}
const saveForm = (e) => {
e.preventDefault()
setResult(result.concat(input))
}
const removeItems = (data) => {
setResult(result.filter(todo => todo.title === data.title));
}
console.log(result)
return(
<ul>
<button onClick={togglePopup}>Work Experience</button>
{result.map((data) => (
<>
<p key={data.title}>{data.title}</p>
<p>{data.company}</p>
<p>{data.date}</p>
<p>{data.location}</p>
<p>{data.description}</p>
<button onClick={removeItems}>Remove</button>
</>
))}
{toggle && <form>
<div>
<label>Job Title</label>
</div>
<div>
<input value={input.title} onChange={ e => {setInput({ title: e.target.value }) }}/>
</div>
<div>
<label>Company</label>
</div>
<div>
<input onChange={ e => {setInput({...input, company: e.target.value }) }}/>
</div>
<div>
<label>Date Worked (MM/YYYY - MM/YYYY)</label>
</div>
<div>
<input onChange={ e => {setInput({...input, date: e.target.value }) }}/>
</div>
<div>
<label>Location (e.g. Los Angeles, CA)</label>
</div>
<div>
<input onChange={ e => {setInput({...input, location: e.target.value }) }}/>
</div>
<div>
<label>Description</label>
</div>
<div>
<input onChange={ e => {setInput({...input, description: e.target.value }) }}/>
</div>
<button onClick={saveForm}>Save</button>
<button onClick={togglePopup}>Cancel</button>
</form>}
</ul>
)
}
export default Experience
You need to pass particular object to match and remove like-
<button onClick={() => removeItems(data)}>Remove</button>
Improved:
{result.map((data) => (
<>
<p key={data.title}>{data.title}</p>
<p>{data.company}</p>
<p>{data.date}</p>
<p>{data.location}</p>
<p>{data.description}</p>
<button onClick={() => removeItems(data)}>Remove</button>
</>
))}
function -> remove particular which is clicked.
const removeItems = (data) => {
const updated = result.filter(todo => todo.title !== data.title)
setResult([...updated]);
}

How to get data from the form when clicking?

I have form inside the component:
const MyPopup = ({ name, authenticity_token }) => {
<form className="new_review" id="new_review" action="/reviews" acceptCharset="UTF-8" method="post">
<input name="utf8" type="hidden" value="✓" />
<input type='hidden' name='authenticity_token' value={authenticity_token} />
<input value="2" type="hidden" name="review[reviewable_id]" id="review_reviewable_id" />
<Popup
// ...
footer={
<SendButton
onClick={() => {
setMessageShown(true);
}}
/>
}
// ...
>
<div className="input-group input-group_indent-b_default">
<label className="input-group__label" name='review[email]'>email</label>
<input className="input-group__input" name='review[email]' type="email" />
</div>
</form>
You need to send the data of this form to the server. Ajax request. How do I get form data when I click on submit?
const SendButton = () => (
<button
onClick={e => {
const data = new FormData(e.target);
}}
className="button popup-footer__button"
>
Отправить
</button>
);
const data is empty
Try to abstract the submit functionality away from the button itself. Define a handleSubmit() function and pair it with the form's onSubmit handler. Let the button be as simple as possible, you can still have it do whatever visual actions or other functionality, but let the form handle the actual submit functionality.
You can do something like the following to extract the data from the form:
Working Sandbox: https://codesandbox.io/s/hardcore-austin-bhq8m
MyPopup:
import React from "react";
import Popup from "./Popup";
const handleSubmit = e => {
e.preventDefault();
const data = new FormData(e.target);
const dataIterator = Array.from(data);
const postObject = dataIterator.reduce((obj, [key, value]) => {
return {
...obj,
[key]: value
};
}, {});
console.log(postObject);
};
const MyPopup = ({ name, authenticity_token }) => {
return (
<form
onSubmit={handleSubmit}
className="new_review"
id="new_review"
action="/reviews"
acceptCharset="UTF-8"
method="post"
>
<input name="utf8" type="hidden" value="✓" />
<input
type="hidden"
name="authenticity_token"
value={authenticity_token}
/>
<input
value="2"
type="hidden"
name="review[reviewable_id]"
id="review_reviewable_id"
/>
<div className="input-group input-group_indent-b_default">
<label className="input-group__label" name="review[email]">
email
</label>
<input
className="input-group__input"
name="review[email]"
type="email"
/>
<Popup />
</div>
</form>
);
};
export default MyPopup;
Popup
import React from "react";
const Popup = props => {
return <button type="submit">Submit</button>;
};
export default Popup;
The postObject includes all the data from the form, I'm assuming this is what you want to do your request :)
You need to have this:
onClick={e => {
const data = new FormData(e.target);
}}
As onSubmit to your form instead of having it as onClick to the submit button, the button will be responsible for invoking the form's onSubmit callback function, also give the button type='submit':
onSubmit={e => {
e.preventDefault();
const data = new FormData(e.target);
console.log('works!', data)
}}
Reproduced:
const MyPopup = ({ name, authenticity_token }) => {
<form
className="new_review"
id="new_review"
action="/reviews"
acceptCharset="UTF-8"
method="post"
onSubmit={e => {
e.preventDefault();
const data = new FormData(e.target);
console.log('works!', data)
}}
>
<Popup
// ...
footer={
<SendButton
onClick={() => {
setMessageShown(true);
}}
/>
}
// ...
>
</form>
const SendButton = () => (
<button
type='submit'
className="button popup-footer__button"
>

Categories

Resources