Right now the form is allowing empty and non valid email strings to be stored to my firestore.
In regular html input tag i know using required and type=email forces the validation.
Is there not something similar using Chakra Ui?
const SubscribeForm = () => {
const [input, setInput] = useState("");
const isError = input === ''
const handleSubmit = (e) => {
console.log("saved to firestore , input: " + input)
e.preventDefault();
saveEmail(input);
setInput("Thanks for subscribing!");
};
const saveEmail = async (input) => {
try {
const docRef = await addDoc(collection(db, "sub-emails"), {
email: input
});
console.log("Document written with ID: ", input);
} catch (e) {
console.error("Error adding document: " + input, e);
}
};
return (
<FormControl isRequired >
<Text paddingBottom="10px" fontSize="14px" color="white" > Get updated when site goes live!</Text>
<Input
isRequired
value={input}
onChange={(e) => setInput(e.target.value)} fontSize="13px" placeholder="example#gmail.com" bgColor="white" id='email' type='email' />
<Button
onClick={handleSubmit}
mt={4}
colorScheme='teal'
type='submit'
>
Submit
</Button>
</FormControl>
)
}
export default SubscribeForm
Doesn't seem like the isRequired and type='email' is working
Create a custom function like this:
const isValidEmail = /^[\w-\.]+#([\w-]+\.)+[\w-]{2,4}$/g;
const validateEmail = (e) => {
if(e.target?.value && e.target.value.match(isValidEmail)){
showNoValidEmail(false);
setInput(e.target.value)
}else{
showNoValidEmail(true);
}
}
Where showNoValidEmail it's a boolean state and can be used with a custom html message.
Now, in your handleSubmit you can do this:
const handleSubmit = (e) => {
console.log("saved to firestore , input: " + input)
e.preventDefault();
if(input && input.length && input.match(isValidEmail)){
saveEmail(input);
setInput("Thanks for subscribing!");
}else{
//show a error message or something like that
}
};
Related
const [name, setName] = useState("");
const [age, setAge] = useState("");
const initialValues = {
name: "",
age: "",
};
const [formValues, setFormValues] = useState(initialValues);
const [formErrors, setFormErrors] = useState({});
const [isSubmit, setIsSubmit] = useState(false);
const handleChange = (e) => {
const { name, value } = e.target;
setFormValues({ ...formValues, [name]: value });
};
const handleSubmit = (e) => {
setFormErrors(validate(formValues));
setIsSubmit(true);
};
const validate = (values) => {
const errors = {};
if (!values.name) {
errors.name = "Name is required";
}
if (!values.age) {
errors.age= "Age is required";
}
return errors;
};
const userCreate = async () => {
await api.post("/createuser", {
name,
age,
});
};
return (
<div class="container">
<Form
onSubmit={
Object.keys(formErrors).length === 0 && isSubmit
? userCreate
: handleSubmit
}
>
<Form.Field>
<label>Name</label>
<input
name="name"
onChange={(e) => {
setName(e.target.value);
handleChange(e);
}}
values={formValues.name}
/>
<span className="error-message">{formErrors.name}</span>
</Form.Field>
<Form.Field>
<label>Age</label>
<input
name="age"
onChange={(e) => {
setAge(e.target.value);
handleChange(e);
}}
values={formValues.age}
/>
<p className="error-message">{formErrors.age}</p>
</Form.Field>
<Button type="submit">Submit</Button>
</Form>
</div>
);
I'm trying to use axios to do POST method for creating user.
I got everything works fine but there's one small problem but I don't know how to fix.
The problem is that I always need to submit the form 2 times to make the POST request. There's nothing happen in the first submit, but it will work in the second submit.
Does anyone know what's wrong with my code?
Edited
According to #DBS solution.
I'm trying to follow the steps but now the form can't submit anymore. Can someone let me know if I missed something?
const [name, setName] = useState("");
const [age, setAge] = useState("");
const initialValues = {
name: "",
age: "",
};
const [formValues, setFormValues] = useState(initialValues);
const [formErrors, setFormErrors] = useState({});
const [isSubmitting, setIsSubmitting] = useState(false);
const handleChange = (e) => {
const { name, value } = e.target;
setFormValues({ ...formValues, [name]: value });
};
const handleSubmit = (e) => {
if (!Object.keys(formErrors).length && !isSubmitting) {
setFormErrors(validate(formValues));
} else {
userCreate();
setisSubmitting(true);
}
};
const validate = (values) => {
const errors = {};
if (!values.name) {
errors.name = "Name is required";
}
if (!values.age) {
errors.age= "Age is required";
}
return errors;
};
const userCreate = async () => {
await api.post("/createuser", {
name,
age,
});
};
return (
<div class="container">
<Form
onSubmit={handleSubmit}
>
<Form.Field>
<label>Name</label>
<input
name="name"
onChange={(e) => {
setName(e.target.value);
handleChange(e);
}}
values={formValues.name}
/>
<span className="error-message">{formErrors.name}</span>
</Form.Field>
<Form.Field>
<label>Age</label>
<input
name="age"
onChange={(e) => {
setAge(e.target.value);
handleChange(e);
}}
values={formValues.age}
/>
<p className="error-message">{formErrors.age}</p>
<
The issue here is your isSubmit, it is required to be true for userCreate to be called:
onSubmit={
Object.keys(formErrors).length === 0 && isSubmit
? userCreate
: handleSubmit
}
But it starts as false:
const [isSubmit, setIsSubmit] = useState(false);
And is only ever updated when handleSubmit is called (which, confusingly, is only called when the validation fails)
So your current code does this:
isSubmit is false
Submit is clicked, handleSubmit is called and isSubmit is set to true
Submit is clicked again, now isSubmit is true it will call userCreate
To solve this, there are a few different approaches, but I would:
Move all the submit handler logic into onSubmit={handleSubmit} (To keep things clear)
Inside there, do your error length check (0 error) and isSubmit (Which I would probably rename to isSubmitting for clarity, and make sure it's false) (E.g. !Object.keys(formErrors).length && !isSubmitting)
If there are errors, show the appropriate message (Leaving isSubmitting as false)
If not, call userCreate (And set isSubmitting to true)
Lastly, if this can be submitted multiple times, add an effect/callback/then to reset isSubmitting once the call is complete.
Are you using the isSubmitting flag for something? if not below might be work for you.
If there is no error, calling the create method
const handleSubmit = (e) => {
setFormErrors(validate(formValues));
if(Object.keys(formErrors).length === 0) {
userCreate();
}
};
if isSubmitting is used to check the submit or create in progress
const handleSubmit = (e) => {
setFormErrors(validate(formValues));
if(Object.keys(formErrors).length === 0) {
setIsSubmitting(true);
userCreate();
}
};
The flag isSubmitting should be set as false on API is success or failed
setIsSubmitting(false)
I have a formik form with a select field; two options. When i use onClick I always get "yes" submitted and if i use onChange it does not work in that it does not allow me to choose anything, just always leaves the field the same as before.
I have read a ton of different things. I have tried the setFieldValue, and I have tried onBlur, I have tried numerous different ways in writing the onChange handler without any success. Maybe i am just not changing and writing it properly.
I have looked over the suggested questions already on here and for whatever reason i can not get them to work in my code.
import React, { useState, useRef } from 'react';
import { Form, Field, } from 'formik';
import emailjs from '#emailjs/browser';
const RsvpForm = ({ errors, touched, isValid, dirty }) => {
const form = useRef();
const sendEmail = (e) => {
e.preventDefault();
const userName = e.target[0].value;
const email = e.target[1].value;
const attending = state;
const plusOne = plusone;
const guests = e.target[4].value;
const guestNumber = e.target[5].value;
const guest_name = e.target[6].value;
const song = e.target[7].value;
const message = e.target[8].value;
let templateParams = {
userName: userName,
email: email,
attending: attending,
plusOne: plusOne,
guests: guests,
guestNumber: guestNumber,
guest_name: guest_name,
song: song,
message: message,
};
emailjs.send(process.env.REACT_APP_SERVICE_ID, process.env.REACT_APP_TEMPLATE_ID, templateParams, process.env.REACT_APP_PUBLIC_KEY)
.then((result) => {
console.log(result.text);
e.target.reset();
}, (error) => {
console.log(error.text);
});
};
const[state, attendingState] = useState("");
const onClick = (e) => {
let{value} = e.target;
if(value=== 'yes') {
attendingState('yes')
}else {
attendingState('no')
}
}
const[plusone, plusOnestate] = useState("");
const onPick = (e) => {
let{value} = e.target;
if(value=== 'no') {
plusOnestate('no')
}else {
plusOnestate('yes')
}
}
return (
<div className='form-group'>
<label className='col-form-label'>Plus One:</label>
<Field
component='select'
className={
touched.plusOne
? `form-control ${errors.plusOne ? 'invalid' : 'valid'}`
: `form-control`
}
name='plusOne'
type='select'
// onChange={(e) => setFieldValue('plusOne', e.target.value)}
onClick={onPick}
>
<option value="">Please select an answer</option>
<option value="yes">Yes, please add a plus one or few</option>
<option value="no">Just me!</option>
</Field>
{touched.plusOne && errors.plusOne && (
<small className='text-warning'><strong>{errors.plusOne}</strong></small>
)}
</div>
I think the title is self-explanatory. What am I doing wrong below? What I want to achieve is getting the text out of a photo, right after the user selects a photo.
The error I get is:
createWorker.js:173 Uncaught Error: RuntimeError: null function or function signature mismatch
What am I doing wrong?
const { createWorker } = require("tesseract.js");
const [file,setFile] = useState();
const worker = createWorker({
logger: (m) => console.log(m),
});
const doOCR = async (image) => {
await worker.load();
await worker.loadLanguage("eng");
await worker.initialize("eng");
const {
data: { text },
} = await worker.recognize(image);
// } = await worker.recognize('https://tesseract.projectnaptha.com/img/eng_bw.png');
console.log(text);
setOcr(text);
};
const [ocr, setOcr] = useState("Recognizing...");
useEffect(() => {
file ? doOCR(file) : console.log('no file selected yet!');
}, [file]);
const getFile = (e) => {
console.log("Upload event:", e);
if (e) {
if (Array.isArray(e)) setFile(e[0]);
setFile(e)
}
}
....
<p>{ocr}</p> /* this only displays "Recognizing..." */
<Form.Item
name="uploadedPhoto"
label="Upload your photo scan"
getValueFromEvent={getFile}
// rules={[{ required: true }]}>
<Input type="file"
// onChange={onImageUpload}
/>
</Form.Item>
Solved it by doing it like this instead of the above (I applied the function to the onChange of the Input itself, not the Form.Item element)
const handleFileSelected = (e) => {
const files = Array.from(e.target.files);
setFile(files[0]);
};
<Input type="file" onChange={handleFileSelected} />
In React, I have a textbox with a Submit button that is visible when the user clicks 'Wave At Me' and is not visible after the user clicks 'Submit'. What do I put for value in the input tag? How do I get value should I can use it in the setFormText method? In the component class, value is below, but what is the equivalent for the function code?
<input type="text" value={this.state.value} onChange={this.handleChange} />
My code is below in the default App() function, currently the user is unable to change the text:
const [currentVisibility, setVisibility] = useState(false);
const [currentFormText, setFormText] = useState("");
//wave at me button just shows the form
const wave = async () => {
setVisibility(true);
console.log("form appears")
}
// I don't think it's correct to use changeValue function
const changeValue = async () => {
console.log("formed had some text");
}
const handleChange = async () => {
console.log("form was changed");
}
//the handle submit should read the value from the input field to use in the parameter string of the wave() function.
const handleSubmit = async () => {
try {
setVisibility(false);
const { ethereum } = window;
if (ethereum) {
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const wavePortalContract = new ethers.Contract(contractAddress, contractABI, signer);
let count = await wavePortalContract.getTotalWaves();
console.log("Retrieved total wave count...", count.toNumber());
//change to currentText instead of water bottle
const waveTxn = await wavePortalContract.wave("water bottle");
console.log("Mining...", waveTxn.hash);
await waveTxn.wait();
console.log("Mined -- ", waveTxn.hash);
count = await wavePortalContract.getTotalWaves();
console.log("Retrieved total wave count...", count.toNumber());
} else {
console.log("Ethereum object does not exist!");
}
} catch (error) {
console.log(error)
}
}
return {currentVisibility && (
<form onSubmit={handleSubmit}>
<label>
Message:
<input type="text" value="" onChange={handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
)}
The useState hook returns the state value and a setter function. So in your case, currentFormText is the state value and setFormText is the setter function. Thus, your input should read:
<input type="text" value={currentFormText} onChange={handleChange} />
If you do this, you'll notice you can't change the input's value. That's because React is now "controlling" the value of the input; in other words, React is now the "source of truth" for this input (rather than the browser/HTML itself). Because of this, you'll need to add to your handler function:
// we certainly don't need the `async` keyword here!
const handleChange = (event) => {
console.log("form was changed");
setFormText(event.target.value);
}
On form submit refresh the page, you need to put this code e.preventDefault(); in handleSubmitfunction !
When handleChange function call you need to set the input value in currentFormText state that's why you unable to change the text !
Try this code it's work for me
function App() {
const [currentVisibility, setVisibility] = useState(true);
const [currentFormText, setFormText] = useState("");
//wave at me button just shows the form
const wave = async () => {
setVisibility(true);
console.log("form appears")
}
const changeValue = async () => {
console.log("formed had some text");
}
const handleChange = async (value) => {
setFormText(value)
console.log("form was changed");
}
//the handle submit should read the value from the input field to use in the parameter string of the wave() function.
const handleSubmit = async (e) => {
try {
e.preventDefault();
setVisibility(false);
const { ethereum } = window;
if (ethereum) {
const provider = new ethers.providers.Web3Provider(ethereum);
const signer = provider.getSigner();
const wavePortalContract = new ethers.Contract(contractAddress, contractABI, signer);
let count = await wavePortalContract.getTotalWaves();
console.log("Retrieved total wave count...", count.toNumber());
//change to currentText instead of water bottle
const waveTxn = await wavePortalContract.wave("water bottle");
console.log("Mining...", waveTxn.hash);
await waveTxn.wait();
console.log("Mined -- ", waveTxn.hash);
count = await wavePortalContract.getTotalWaves();
console.log("Retrieved total wave count...", count.toNumber());
} else {
console.log("Ethereum object does not exist!");
}
} catch (error) {
console.log(error)
}
}
return (
currentVisibility &&
<form onSubmit={(e) => handleSubmit(e)}>
<label>
Message:
<input type="text" value={currentFormText} onChange={(e) => handleChange(e.target.value)} />
</label>
<input type="submit" value="Submit" />
</form>
)
}
export default App;
I am trying to create a real time search and real time populating users.
Here is how my page look like:
Right now my search function is I have to click search icon to make it appear the result so I want to change that to real time search. When I type the name in input it will auto starting appear the user card for me
Here is my code in SearchForMembers.js:
const SearchForMembers = ({ teamId, fetchTeamData }) => {
// State
const [userResults, setUserResults] = useState([]);
const [userSkillResults, setUsersSkillsResults] = useState([]);
const [showResultsList, setShowResultsList] = useState(false);
const [showResultsMsg, toggleResultsMsg] = useState(false);
// Submit search query
const searchForTerm = async (term) => {
try {
if (term !== undefined) {
// Clear results
setUserResults([]);
setUsersSkillsResults([]);
// Perform search
const res = await axios.get(`/api/v1/search/users/${term}`);
// Check response
// Show message if no results were found
if (res.data[0].length === 0 && res.data[1].length === 0) {
toggleResultsMsg(true);
} else {
toggleResultsMsg(false);
// Set users results
setUserResults(res.data[0]);
// Set skills results
setUsersSkillsResults(res.data[1]);
}
}
} catch (err) {
throw new Error(err);
}
};
useEffect(() => {
if (userResults.length > 0 || userSkillResults.length > 0) {
setShowResultsList(true);
} else {
setShowResultsList(false);
}
}, [userResults, userSkillResults]);
return (
<div className="container--search_for_members">
{/* Search bar */}
<SearchBar
linkToPage={false}
searchForTerm={searchForTerm}
placeHolderText="Search for a name, skill or affiliation"
/>
{/* Results list */}
{showResultsList && (
<SearchForMembersResults
usersFound={userResults}
userSkillResults={userSkillResults}
teamId={teamId}
fetchTeamData={fetchTeamData}
/>
)}
{showResultsMsg && (
<>
<p className="text--message-small">No results were found</p>
<AddNewProfile
teamId={teamId}
fetchTeamData={fetchTeamData}
variant="not in table"
/>
</>
)}
</div>
);
};
And here is my code in SearchBar,js :
const SearchBar = ({
linktoPage,
searchForTerm,
placeHolderText = "Search members or teams",
}) => {
// Search state
const [searchTerm, setSearchTerm] = useState("");
const handleChange = (event) => {
// Update state with input text
event.preventDefault();
setSearchTerm(event.target.value);
};
const handleSubmit = async (event) => {
try {
event.preventDefault();
if (linktoPage) {
// Go to page and pass query
goToPage();
} else {
// Don't change pages, but pass term to search method
searchForTerm(searchTerm);
}
} catch (err) {
throw new Error(err);
}
};
const goToPage = () => {
// Go to search page and pass along the search term.
Router.push({
pathname: "/search",
query: { term: `${searchTerm}` },
});
};
return (
<form className="form--search_wrapper" method="GET" onSubmit={handleSubmit}>
<input
className="input input--search_input"
type="search"
name="q"
placeholder={placeHolderText}
aria-label="Search bar"
onInput={handleChange}
pattern="^[a-zA-Z0-9 ]+"
required
/>
<Button className="input input--search" style={{ color: "white", backgroundColor: "#00B790" }} type="submit" >
<SearchRoundedIcon />
</Button>
</form>
);
};
I read about the live search with axios. Here is the link: https://www.digitalocean.com/community/tutorials/react-live-search-with-axios
How can I use .filter in my code ?
You can directly call the body of your handleSubmit function in the handleChange function, you probably want to debounce it so you don't call your api for every keystroke though
const handleChange = (event) => {
// Update state with input text
event.preventDefault();
setSearchTerm(event.target.value);
try {
if (linktoPage) {
// Go to page and pass query
goToPage();
} else {
// Don't change pages, but pass term to search method
searchForTerm(event.target.value);
}
} catch (err) {
throw new Error(err);
}
};