react axios post method - javascript

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);
});
};

Related

Having an issue with shipping options

I have a problem fetching the shipping options, the error: 'Unhandled Rejection (TypeError): undefined is not an object (evaluating 'options[0].id')'. I have checked everything I can think of to debug this issue. I am using check.io as for my e-commerce backend. I have added different shipping option on that site however they are not showing up. I have a hard time understanding why there is a type error
import React, { useState, useEffect } from "react";
import {
InputLabel,
Select,
MenuItem,
Button,
Grid,
Typography,
} from "#material-ui/core";
import { useForm, FormProvider } from "react-hook-form";
import { Link } from "react-router-dom";
import FormInput from "../CheckoutForm/CustomTxtField";
import { commerce } from "../../lib/Commerce";
const AddressForm = ({ checkoutToken, test }) => {
const [shippingCountries, setShippingCountries] = useState([]);
const [shippingCountry, setShippingCountry] = useState("");
const [shippingSubdivisions, setShippingSubdivisions] = useState([]);
const [shippingSubdivision, setShippingSubdivision] = useState("");
const [shippingOptions, setShippingOptions] = useState([]);
const [shippingOption, setShippingOption] = useState("");
const methods = useForm();
const fetchShippingCountries = async (checkoutTokenId) => {
const { countries } = await commerce.services.localeListShippingCountries(
checkoutTokenId
);
setShippingCountries(countries);
setShippingCountry(Object.keys(countries)[0]);
};
const fetchSubdivisions = async (countryCode) => {
const { subdivisions } = await commerce.services.localeListSubdivisions(
countryCode
);
setShippingSubdivisions(subdivisions);
setShippingSubdivision(Object.keys(subdivisions)[0]);
};
const fetchShippingOptions = async (
checkoutTokenId,
country,
stateProvince = null
) => {
const options = await commerce.checkout.getShippingOptions(
checkoutTokenId,
{ country, region: stateProvince }
);
setShippingOptions(options);
setShippingOptions(options[0].id);
};
useEffect(() => {
if (checkoutToken && checkoutToken.id) {
fetchShippingCountries(checkoutToken.id);
console.log(checkoutToken.id);
}
}, [checkoutToken]);
useEffect(() => {
if (shippingCountry) fetchSubdivisions(shippingCountry);
}, [shippingCountry]);
useEffect(() => {
if (shippingSubdivision)
fetchShippingOptions(
checkoutToken.id,
shippingCountry,
shippingSubdivision
);
}, [shippingSubdivision]);
return (
<div>
<Typography variant="h6" gutterBottom>
Shipping address
</Typography>
<FormProvider {...methods}>
<form
onSubmit={methods.handleSubmit((data) =>
test({
...data,
shippingCountry,
shippingSubdivision,
shippingOption,
})
)}
>
<Grid container spacing={3}>
<FormInput name="firstName" label="First name" />
<FormInput name="lastName" label="Last name" />
<FormInput name="address1" label="Address line 1" />
<FormInput name="email" label="Email" />
<FormInput name="city" label="City" />
<FormInput name="zip" label="Zip / Postal code" />
<Grid item xs={12} sm={6}>
<InputLabel>Shipping Country</InputLabel>
<Select
value={shippingCountry}
fullWidth
onChange={(e) => setShippingCountry(e.target.value)}
>
{Object.entries(shippingCountries)
.map(([code, name]) => ({ id: code, label: name }))
.map((item) => (
<MenuItem key={item.id} value={item.id}>
{item.label}
</MenuItem>
))}
</Select>
</Grid>
<Grid item xs={12} sm={6}>
<InputLabel>Shipping Subdivision</InputLabel>
<Select
value={shippingSubdivision}
fullWidth
onChange={(e) => setShippingSubdivision(e.target.value)}
>
{Object.entries(shippingSubdivisions)
.map(([code, name]) => ({ id: code, label: name }))
.map((item) => (
<MenuItem key={item.id} value={item.id}>
{item.label}
</MenuItem>
))}
</Select>
</Grid>
<Grid item xs={12} sm={6}>
<InputLabel>Shipping Options</InputLabel>
<Select
value={shippingOption}
fullWidth
onChange={(e) => setShippingOption(e.target.value)}
>
{shippingOptions
.map((sO) => ({
id: sO.id,
label: `${sO.description} - (${sO.price.formatted_with_symbol})`,
}))
.map((item) => (
<MenuItem key={item.id} value={item.id}>
{item.label}
</MenuItem>
))}
</Select>
</Grid>
</Grid>
<br />
<div style={{ display: "flex", justifyContent: "space-between" }}>
<Button component={Link} variant="outlined" to="/cart">
Back to Cart
</Button>
<Button type="submit" variant="contained" color="primary">
Next
</Button>
</div>
</form>
</FormProvider>
</div>
);
};
export default AddressForm;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
This was a commercejs.com issue not a coding issue

How to get the field values in react material ui components

This works but the when i console log the object it gives
{ "week":undefined, "name":undefined, "code":undefined }
Moreover does wrapping all the material ui component in form tag and treating the whole code as a form, is it appropriate?
here is my code:
const ExamSimulatorForm = () => {
const weekNumber = useRef();
const examSub = useRef();
const examCode = useRef();
const handleSubmit = (event) =>{
event.preventDefault()
const week = weekNumber.current.value
const subject = examSub.current.value
const code = examCode.current.value
const examSimulatorPayload = {
week:week,
subject:subject,
code:code
}
console.log(examSimulatorPayload)
}
const [code, setCode] = useState('Quiz');
const [examSubject, setExamSubject] = useState('');
const [field, setField] = useState(1)
const handleESubjectChange = (event) => {
setExamSubject(event.target.value);
};
const handleCode = (event) => {
setCode(event.target.value);
};
return (
<form >
<CardActions onSubmit={handleSubmit}>
<Grid container spacing={2} justifyContent='center' alignItems='center' direction='column'>
<Grid item>
<TextField
InputProps={{
inputProps: {
max: 12, min: 1
}
}}
label='Week'
type='number'
onChange={(event)=>setField(parseInt(event.target.value))}
style={{minWidth:250}}
ref = {weekNumber}
required
/>
</Grid>
<Grid item>
<FormControl style={{minWidth:250}}>
<InputLabel>Subject</InputLabel>
<Select
value={examSubject}
onChange={handleESubjectChange}
ref={examSub}
required
>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item>
<FormControl style={{minWidth:250}}>
<InputLabel id="exam-code" >Exam Code</InputLabel>
<Select
labelId="exam-code"
id="exam-code-select"
value={code}
onChange={handleCode}
ref={examCode}
required
>
<MenuItem value={'Q'}>Q</MenuItem>
<MenuItem value={'M'}>M</MenuItem>
<MenuItem value={'F'}>F</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item>
<Button variant='contained' color='primary' style={{marginTop:94}} >Take Exam</Button>
</Grid>
</Grid>
</CardActions>
</form>
)
}
export default ExamSimulatorForm;
I have a similar form for attendance simulation, attendance dataset generation and exam dataset generation
I think this is good for you.
Please try this.
const ExamSimulatorForm = () => {
const [state, setState] = useState({
code: 'Quiz',
subject: '',
week: 1
});
const handleSubmit = (event) =>{
event.preventDefault()
const examSimulatorPayload = state;
console.log(examSimulatorPayload)
}
const handleChange = (evt, name) {
const { value } = evt.target;
setState({
...state,
[name]: value
});
}
return (
<form onSubmit={handleSubmit}>
<CardActions>
<Grid container spacing={2} justifyContent='center'
alignItems='center' direction='column'>
<Grid item>
<TextField
InputProps={{
inputProps: {
max: 12, min: 1
}
}}
label='Week'
type='number'
value={state.week}
onChange={(event)=>handleChange( event, "week")}
style={{minWidth:250}}
required
/>
</Grid>
<Grid item>
<FormControl style={{minWidth:250}}>
<InputLabel>Subject</InputLabel>
<Select
value={state.subject}
onChange={(event)=>handleChange( event, "subject")}
required
>
<MenuItem value={10}>Ten</MenuItem>
<MenuItem value={20}>Twenty</MenuItem>
<MenuItem value={30}>Thirty</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item>
<FormControl style={{minWidth:250}}>
<InputLabel id="exam-code" >Exam Code</InputLabel>
<Select
labelId="exam-code"
id="exam-code-select"
value={state.code}
onChange={(event)=>handleChange( event, "code")}
required
>
<MenuItem value={'Q'}>Q</MenuItem>
<MenuItem value={'M'}>M</MenuItem>
<MenuItem value={'F'}>F</MenuItem>
</Select>
</FormControl>
</Grid>
<Grid item>
<Button variant='contained' color='primary' style=
{{marginTop:94}} >Take Exam</Button>
</Grid>
</Grid>
</CardActions>
</form>
)
}
export default ExamSimulatorForm;
Please check it above code, and let me know your idea.
State updates in react are asynchronus, which means they don't occur as soon as you call them. You have to wait until the state updates to console.log because otherwise, nothing has changed and you are getting the initial value. You could do something like this:
useEffect(() => {
const subject = examSub.current.value
console.log(subject)
}, [examSubject])
useEffect() executes an action every time a state changes. Notice how at the end there is an array, with [examSubject]. This signifies the state that will trigger the effect. So when examSubject changes (when you assign a value to it), the effect will execute (in this case, it will log the subject).
When writing code, at least in my case, you don't need to worry about this. You can chnage the state and write your code as normal, but react might take a second or two to update the state. The only time I really notice this is when I console.log.
You can define the state for your inputs :
const [code, setCode] = React.useState('');
const [subject, setSubject] = React.useState('');
const [week, setWeek] = React.useState('');
const setExamCode = event => {
setCode(event.target.value);
};
const setSubject = event => {
setSubject(event.target.value);
};
const setWeek = event => {
setWeek(event.target.value);
};
Then call these methods from onChange event like : onChange={setExamCode} or {setSubject}
In case you want to handle data from single event and defining it's initial state try below approach :
const initialData = Object.freeze({
code: "",
subject: "",
week: ""
});
const [data, updateData] = React.useState(initialData );
const handleChange = (e) => {
updateData({
...data,
[e.target.name]: e.target.value
});
};
const handleSubmit = (e) => {
e.preventDefault()
console.log(data);
};
Then call these methods from onChange event like onChange={handleSubmit}

React - How to return Axios catch errors inline inside my form?

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>}
//....
)

Checkbox value is not passed properly to the backend API

I have a registration page created in ReactJS. One of the fields is a checkbox isadult. When I click on Register button and save the fields in a database (MongoDB), the value of isadult appears as [Object object] instead of a concrete value: True or False.
What am I doing wrong?
import React from 'react';
import { Paper, makeStyles, Grid, TextField, Button, Switch } from '#material-ui/core';
import config from '../../config/config.json';
import axios from 'axios';
const useStyles = makeStyles((theme) => ({
root: {
minWidth: '300px',
width: '50%',
padding: '20px 20px 20px 20px',
margin: 'auto'
}
}));
const Register = () => {
const classes = useStyles();
const [username, setUsername] = React.useState('');
const [password, setPassword] = React.useState('');
const [isadult, setIsAdult] = React.useState('');
const handleChangeIsAdult = (event) => {
setIsAdult({
...isadult,
[event.target.name]: event.target.value,
});
}
const handleRegister = () => {
if (username && password) {
const formData = new FormData();
formData.append('username', username);
formData.append('password', password);
formData.append('isadult', isadult);
axios.post(config.api.url + '/auth/register', formData)
.then(res => {
console.log(res)
})
.catch(err => {
console.log(err)
})
}
}
return (
<Paper className={classes.root}>
<div >
<Grid container spacing={8} alignItems="flex-end">
<Grid item md={true} sm={true} xs={true}>
<TextField
id="username"
label="Username"
type="email"
fullWidth
value={username}
onChange={(e) => setUsername(e.target.value)}
autoFocus />
</Grid>
</Grid>
<Grid container spacing={8} alignItems="flex-end">
<Grid item md={true} sm={true} xs={true}>
<TextField
id="password"
label="Password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
fullWidth />
</Grid>
</Grid>
<Grid container spacing={8} alignItems="flex-end">
<Grid item md={true} sm={true} xs={true}>
<label>Is adult?</label>
<input
type='checkbox'
onChange={(event) => {
handleChangeIsAdult({
target: {
name: event.target.name,
value: event.target.checked,
},
});
}}
/>
</Grid>
</Grid>
<Grid container justify="center" style={{ marginTop: '10px' }}>
<Button
variant="outlined"
color="primary"
style={{ textTransform: "none" }}
onClick={handleRegister}
>
Register
</Button>
</Grid>
</div>
</Paper>
);
}
export default Register;
As your isadult state property is intended for use in the checkbox input, it needs to be declared and updated as a boolean.
You are declaring the propery as follows:
const [isadult, setIsAdult] = React.useState('');
The initial assignment is the empty string (''), which may cause issues with other places in your application code if they expect that property to be of type boolean. What you should do instead is start it off as a boolean:
const [isadult, setIsAdult] = React.useState(false);
Now, the main problem you are facing is the fact that the form data is being serialized with isadult being an object. This problem is coming from the fact that you are assigning an object to it through setIsAdult:
setIsAdult({
...isadult,
[event.target.name]: event.target.value,
});
The state property setter appends whatever value is passed to it directly to the property it is attached to. It works differently from setState that expects a state object. The right way to use the method in this case is:
setIsAdult(event.target.value);
Here, event.target.value contains exactly the checkbox checked boolean value that should go into isadult. Now, this property is serialized correctly as a boolean in your formData.

Resetting a form when using onBlur as opposed to onChange

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')}
/>
)

Categories

Resources