I'm quite a newbie with React. I made a login page using firebase auth and have any input field to get the person's contact to validate but I can't get this data. Already tried everything I found here but it is not working.
I tried the ref={x => this.contacto = x} as shown below but not working.
export class Login extends Component {
handleClick=()=>{
const recaptcha = new firebase.auth.RecaptchaVerifier('recaptcha');
const number = this.contacto.value;
console.log(number)
firebase.auth().signInWithPhoneNumber(number, recaptcha).then( function(e) {
var code = prompt('Enter the otp', '');
if(code === null) return;
e.confirm(code).then(function (result) {
console.log(result.user);
document.querySelector('label').textContent += result.user.phoneNumber + "Number verified";
}).catch(function (error) {
console.error( error);
});
})
.catch(function (error) {
console.error( error);
});
}
render(){
return (
<div>
<div id="recaptcha"></div>
<Grid container justify="center">
<Grid item component={Card} xs={6} md={3} className={cx(styles.card)}>
<CardContent>
<img className={styles.image} src={image} alt="cmcq" />
<Typography variant="h6" className={cx(styles.titulo)} gutterBottom>
Login
</Typography>
<TextField
id="outlined-primary"
label="Insert phone number"
variant="outlined"
color="primary"
size="small"
ref={x => this.contacto = x}
className={cx(styles.field)}
/>
<Button variant="contained" color="primary" className={cx(styles.button)} onClick={this.handleClick} >
Entrar
</Button>
</CardContent>
</Grid>
</Grid>
</div>
);
}
};
export default Login;
Try using the onChange handler for TextField to set a state variable. You can reference it with this.state.varName
onTextChange = (event) => {
this.setState({varName: event.target.value});
}
<TextField
id="outlined-primary"
label="Insert phone number"
variant="outlined"
color="primary"
size="small"
onChange={this.onTextChange}
className={cx(styles.field)}
/>
You shouldn't use ref to access data of TextField, you should use onChange callback method to access data, try:
<TextField
onChange={e => console.log(e)}
/>
The logged e contains your expected data. For using ReactJS mindset you should use state and add it to the state and then access to it.
Related
I am getting an error while calling Axios, in React through handle click button and I have created an onlick function. I am getting errors on the last closing bracket.
the errors shows
Line 24:2: Parsing error: Unexpected token, expected "," (24:2)
enter image description here
as a beginner i can't understand what is the problem
please look at the code and tell me what is the problem with handleProducts function
const NewProduct = (props) => {
const [carCompany, setcarCompany] = React.useState([]);
const [carName, setcarName] = React.useState([]);
const [carModel, setcarModel] = React.useState([]);
const [carPrice, setcarPrice] = React.useState([]);
const [Features, setFeatures] = React.useState([]);
const handleProducts = () => {
axios
.post("http://localhost:4000/products/create", {
carCompany,
carName,
carModel,
carPrice,
Features,
}
.then(res=>{console.log(res.data);
})
.catch(error => {
console.error(error);
});
};
return (
<Grid container spacing={3}>
<Grid item xs={12}>
<h1>Enter Car details for Sale</h1>
</Grid>
<Grid item xs={3}></Grid>
<Grid item xs={6}>
<TextField
id="filled-basic"
fullWidth
label="Car Company"
variant="filled"
value={carCompany}
onChange={(e) => setcarCompany(e.target.value)}
/>
<TextField
id="filled-basic"
fullWidth
label="Car Name"
variant="filled"
value={carName}
onChange={(e) => setcarName(e.target.value)}
/>
<TextField
id="filled-basic"
fullWidth
label="Model"
variant="filled"
value={carModel}
onChange={(e) => setcarModel(e.target.value)}
/>
<TextField
id="filled-basic"
fullWidth
label="Price"
variant="filled"
value={carPrice}
onChange={(e) => setcarPrice(e.target.value)}
/>
<TextField
id="filled-basic"
fullWidth
label="Features"
variant="filled"
value={Features}
onChange={(e) => setFeatures(e.target.value)}
/>
</Grid>
<Grid item xs={3}></Grid>
<Grid item xs={3}></Grid>
<Grid item xs={9}>
<Button color="primary" variant="contained" onClick={handleProducts}>
Add Details
</Button>
</Grid>
<Grid>
{carCompany}
{carName}
{carModel}
{carPrice}
{Features}
</Grid>
</Grid>
);
};
export default NewProduct;
You missed a bracket that should close the post method call. I suggest you use consistent indentation so you can see this more clearly in the future. It is up to you how to indent the code - you can put the function call, then and catch in the same column, or you can organize it in any other way that is clearer for you.
Here's the fixed code for handleProducts:
const handleProducts = () => {
axios.post("http://localhost:4000/products/create", {
carCompany,
carName,
carModel,
carPrice,
Features,
}).then(res => {
console.log(res.data);
}).catch(error => {
console.error(error);
});
};
During user-registration, my backend informs the client if an email and/or username are currently in use by someone else. Below is the response logged into a webconsole thanks to Axios catch error.
I would like to map each email and username to the appropriate field.
My form is based off of Material-UI and react-hook-form
Here is the example of the error response provided by my Axios Instance.
{
"email":["This email is already in use"],
"username":["This username is already in use"]
}
Here is my complete react form, I cut some things out to make it easier to read:
export default function SignUp()
{
const { register, control, errors: fieldsErrors, handleSubmit } = useForm()
const onSubmit = (data, e) => {
console.log(data);
axiosInstance
.post(`api/user/register/`, {
email: data.email,
username: data.username,
password: data.password,
})
.then((res) => {
history.push('/login');
console.log(res);
console.log(res.data);
})
.catch(err => {
console.error(err.response.data);
}
)
};
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}></Avatar>
<Typography component="h1" variant="h5">
Sign up
</Typography>
<form className={classes.form} noValidate onSubmit={handleSubmit(onSubmit)}>
<FormControl fullWidth variant="outlined">
<Grid container spacing={2}>
<Grid item xs={12}>
<Controller
name="email"
as={
<TextField
variant="outlined"
required
fullWidth
id="email"
label="Email Address"
name="email"
autoComplete="email"
error={Boolean(fieldsErrors.email)}
onChange={
(evt) =>
{
let key = evt.currentTarget.name;
let value = evt.currentTarget.value;
handleChange({ [key]: value });
}
}
/>
}
control={control}
defaultValue=""
rules={{
required: 'Required',
pattern: {
value: /^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,4}$/i,
message: 'invalid email address'
}
}}
/>
</Grid>
<Grid item xs={12}>
<Controller
name="username"
as={
<TextField
variant="outlined"
required
fullWidth
id="username"
label="Username"
name="username"
onChange={
(evt) => {
let key = evt.currentTarget.name;
let value = evt.currentTarget.value;
handleChange({[key]: value});
}
}
/>
}
control={control}
defaultValue=""
rules={{
required: 'Required',
pattern: {
value: /^(?!.*\.\.)(?!.*\.$)[^\W][\w.]{0,29}$/i,
message: 'Invalid use of characters'
}
}}
/>
{fieldsErrors.username?.type && <p>{fieldsErrors.username?.message}</p>}
</Grid>
<Grid item xs={12}>
<Controller
name="password"
as={
<TextField
variant="outlined"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
onChange={
(evt) =>
{
let key = evt.currentTarget.name;
let value = evt.currentTarget.value;
handleChange({ [key]: value });
}
}
/>
}
control={control}
defaultValue=""
/>
</Grid>
</Grid>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
onClick={handleSubmit}
>
Sign Up
</Button>
</FormControl>
</form>
</div>
</Container>
);
}
I've managed to create the error into a webalert, but that did not look nice. Is there any simple way to implement my catch error into my form?
I use this field error :
{fieldsErrors.username?.type && <p>{fieldsErrors.username?.message}</p>}
As my Regex error to warn users of illegal characters in their username. I was thinking maybe I could add the errors there? But I do not know how to do that.
You can leverage the useState hook to store errors from the API. Then you can use your template to render those errors in the same format that you display your regex errors.
On a side note, for security's sake it's not a great idea to tell a user that an email is already taken. But if your application doesn't have sensitive data then it's not a huge deal.
EDIT: example
export default function SignUp()
{
const [ apiError, setApiError ] = useState(null)
const onSubmit = (data, e) => {
setApiError(null)
axiosInstance
//...
.catch(err => {
setApiError(err.response.data.message)
console.error(err.response.data);
}
)
};
return (
//....
{apiError && <p>{apiError}</p>}
//....
)
How do i pass a validation value from child component to parents component?
i tried to use props but it didn't work . i tried to pass the 'isValidValue' status
Child Component :
function MilikSendiri({isValidValue}) {
const { register, handleSubmit } = useForm()
function sweetAlertclick(){
Swal.fire({
icon: 'success',
title: 'Data anda sudah tersimpan ',
})
}
return (
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={onSubmit}
// validateOnMount
>
{
formik => {
const isValidValue = formik.isValid? ("Data Completed") : ("DData incomplete");
return(
<div>
<div>
Status : {isValidValue}
<label htmlFor="luasTanah"> Luas Tanah </label>
<Field className="formBiodata"
type="text" id="outlined-basic"
placeholder="luasTanah"
fullWidth
id="luasTanah"
name="luasTanah"
margin="normal" variant="outlined"
/>
<ErrorMessage name='luasTanah' component={TextError}/>
</div>
<div>
<label htmlFor="BiayaPBB"> Biaya PBB </label>
<Field className="formBiodata"
type="text" id="outlined-basic"
placeholder="BiayaPBB"
fullWidth
id="BiayaPBB"
name="BiayaPBB"
margin="normal" variant="outlined"
/>
<ErrorMessage name='BiayaPBB' component={TextError}/>
</div>
<Button onClick={sweetAlertclick} type ="submit"
variant="contained" startIcon={<SaveIcon />} color="primary" style={{
marginLeft: '25rem', marginTop: '20px', width: '20rem', height: 45,
fontSize: 22, backgroundColor: '#22689F'}}
disabled={!formik.isDirty && !formik.isValid} >Simpan
</div>
)
}
}
</Formik>
)
}
Parent Component :
function UKTRumah ({isValidValue}) {
return (
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={onSubmit}
// validateOnMount
>
{
formik => {
console.log('Formik props', formik)
return(
<div className ="IsiBiodata">
<Accordion square expanded={expanded === 'panel1'} onChange=.
{handleChange('panel1')} style={{marginLeft: '15rem', marginRight:
'15rem', marginTop: '3rem'}}>
<AccordionSummary aria-controls="panel1d-content" id="panel1d-
header">
<PersonIcon/>
<Typography> Data Rumah</Typography>
<Typography}> { isValidValue }
</Typography>
</AccordionSummary>
<AccordionDetails>
<div className ="IsiBiodata">
<Form>
</div>
</Form>
</div>
</AccordionDetails>
</Accordion>
</div>
)}}
</Formik>
)}
Thank you
Your example code seems to be lacking some key lines to answer the question specifically.
However, generally if it is data that Parent should be aware of, but that the child will make use of, it should be a value of state in the parent, then handed to the child as props. Here's a very small example using functional components:
const Child = ({ formik, setIsValid, isValid }) => {
useEffect(() => {
setIsValid(formik.isValid)
}, [formik.isValid]);
return <input />;
}
const Parent = () => {
const [isValid, setIsValid] = useState(true);
return <Child isValid={isValid} setIsValid={setIsValid} />
}
You can hold the value on your parent and pass a function to change it to your child. I can't really show you that with the code you posted, but I can show an example of what I mean. The parent has a state with an update function setIsValid and passes that to the child. The child can call setIsValid and that will update the isValid value on the parent.
parent
function Parent() {
const [isValid, setIsValid] = useState(false);
return <div>
<Child setIsValid={setIsValid} />
IsValid {isValid}
</div>
}
child
function Child({ setIsValid }) {
return <button onClick={() => setIsValid(true)}>Set Valid</button>
}
So, I'm trying to create a signup form for a web-app - but are running into a few issues.
I'm using hooks with a function to render signup page, which I'm routing to from the login page.
It works fine assuming I return the html directly from the return in the function (signup), but once the signup has been engaged, I wish swap the form for an acknowledge of it being send.
From what I can tell, people simply wrap each html in an arrow function and then toggles between using a bool or similar. But that's where the issues arrive.
TLDR;
One of the signup textfields autocompletes, fetching from an API. The API then saves the content in a hook variable (address). The second I update the address variable, the form seem to reset - cursor going to the first inputfield.
This only happens when I wrap the html in components, not if I insert all the html in the (signup) return.
I tried to clean it up a bit, but the code more or less look like this.
Any help or pointers would be great :)
export default function SignUp(props)
{
const [activeStep, setActiveStep] = React.useState(0);
const [addresses, setAddresses] = React.useState([{ tekst: '' }]);
const APICall = async (e) =>
{
e.preventDefault();
// Fetchs JSON and set Addresses hook
}
const handleSubmit = props => form =>
{
form.preventDefault()
setActiveStep(activeStep + 1);
}
const CreateAccount = (e) =>
{
return (
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Opret konto
</Typography>
<form className={classes.form} noValidate
onSubmit={handleSubmit(props)}>
<Autocomplete
id="address"
options={addresses}
getOptionLabel={(option) => option.tekst}
style={{ width: 300 }}
renderInput={(params) =>
<TextField {...params} label="Combo box" variant="outlined" onChange={userTest} />
}
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Sign Up
</Button>
</form>
</div>
<Box mt={5}>
<Copyright />
</Box>
</Container>
);
}
const CreateAccountACK = () =>
{
return (
<React.Fragment>
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Avatar className={classes.avatar}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Nyt konto oprettet!
</Typography>
<Button
type="button"
variant="contained"
color="primary"
className={classes.submit}
onClick={() => { props.history.push('/') }}
>
Ok
</Button>
</div>
<Box mt={8}>
<Copyright />
</Box>
</Container>
</React.Fragment>
);
}
return (
<div>
{activeStep == 0 ? <CreateAccount /> : <CreateAccountACK />}
</div>
)
}
Got it working by breaking each function into its own functional component, then render these from the main class (signup) using conditionals. Swapping between pages are handled by callback to "handlesubmit" in this function. Pass history as the final page routes back to main. Feel like this isn't the best way of doing this tho =D, but it avoids the issues with re-renders while typing.
So now the Signup just return ...
export default function SignUp(props)
{
const [activeStep, setActiveStep] = React.useState(0);
const handleSubmit = props => form =>
{
form.preventDefault()
console.log(form)
setActiveStep(activeStep + 1);
}
return (
<div>
{activeStep == 0 ? <CreateAccount handleSubmit={handleSubmit} /> : <CreateAccountACK handleSubmit={handleSubmit} history={props.history}/>}
</div>
)
}
And each function, hooks/variables exist in their own file/function.
I had a form that has a lot of lag due to a large amount of state being handled for user's with a large number of job posts etc. I am trying to subdue this lag my switching my onChange to onBlur, this works great. The only problem is that my form no longer gets set to InitialState( empty string). I also have a submit button that I am keeping invalid until all inputs are filled. due to the onblur it remains invalid until I click away from the form. Is there a way I can still reset a form when using onBlur?? and does anyone have a solution to the issue of my button remaining invalid until I click away from the form. My inputs code are as follows:
the handleSubmit function:
const handleSubmit = async e => {
e.preventDefault()
setIsLoading(true)
const fireToken = await localStorage.FBIdToken
await axios
.post(`/job`, formData, {
headers: {
Authorization: `${fireToken}`
}
})
.then(res => {
setOpen(true)
setMessage(res.data)
fetchUser()
setIsLoading(false)
setIsModalOpen(false)
setFormData(INITIAL_STATE)
})
.catch(err => {
setErrors(err.response.data)
console.log(err)
setIsLoading(false)
})
}
The form code:
import React from 'react'
// components
import SelectStatus from './SelectStatus'
// Material UI Stuff
import CircularProgress from '#material-ui/core/CircularProgress'
import Typography from '#material-ui/core/Typography'
import TextField from '#material-ui/core/TextField'
import CardContent from '#material-ui/core/CardContent'
import Button from '#material-ui/core/Button'
import Card from '#material-ui/core/Card'
import Grid from '#material-ui/core/Grid'
// JobCardStyles
import useJobCardStyles from '../styles/JobCardStyles'
const NewJobForm = React.forwardRef(
({ handleSubmit, formData, handleInputChange, isloading }, ref) => {
const { company, position, status, link } = formData
const isInvalid = !company || !position || !link || !status || isloading
const classes = useJobCardStyles()
return (
<Card className={classes.card}>
<CardContent className={classes.content}>
<form noValidate onSubmit={handleSubmit} className={classes.form}>
<Grid
container
spacing={2}
alignItems="center"
justify="space-between"
>
<Grid item sm="auto" xs={12} className={classes.grid}>
<Typography>New</Typography>
<Typography>Job</Typography>
</Grid>
<Grid item sm={3} xs={12} className={classes.grid}>
<TextField
className={classes.jobField}
margin="normal"
fullWidth
id="company"
type="company"
label="Company"
name="company"
autoComplete="company"
defaultValue={company}
onBlur={handleInputChange('company')}
/>
</Grid>
<Grid item sm={3} xs={12} className={classes.grid}>
<TextField
className={classes.jobField}
margin="normal"
fullWidth
id="position"
type="position"
label="Position"
name="position"
autoComplete="position"
defaultValue={position}
onBlur={handleInputChange('position')}
/>
</Grid>
<Grid item sm={2} xs={12} className={classes.grid}>
<SelectStatus
status={status}
handleInputChange={handleInputChange}
/>
</Grid>
<Grid item sm={2} xs={12} className={classes.grid}>
<TextField
className={classes.jobField}
margin="normal"
fullWidth
id="link"
type="text"
label="Link"
name="link"
autoComplete="link"
defaultValue={link}
onBlur={handleInputChange('link')}
/>
</Grid>
<Grid item sm={1} xs={12} className={classes.grid}>
<Button
fullWidth
type="submit"
variant="contained"
color="primary"
disabled={isInvalid}
className={classes.submit}
disableElevation
>
Submit
{isloading && (
<CircularProgress size={30} className={classes.progress} />
)}
</Button>
</Grid>
</Grid>
</form>
</CardContent>
</Card>
)
}
)
export default NewJobForm
Try making another function to wrap several functions.
const NewJobForm = React.forwardRef(
//other logic
const reset = () => {//your reset function logic}
//ver 1
const handleOnBlur = (fn, relatedParam) => {
reset();
fn(relatedParam);
}
//ver 2
const handleOnBlur = (relatedParam) => {
reset();
handleInputChange(relatedParam);
}
return (
<TextField
//other props
onBlur={() => handleOnBlur('company')}
/>
)