React.js displaying error messages next to belonging input fields - javascript

I have created an API login/register system with Django and React.js, I have my Back-End up and running, the registration system itself is fully functioning, what I need right now is a way to display response messages after the API call from React.js to Django. All the errors after API call are being stored as object in the state. So far I just displayed all the messages like this:
What I need now is a way to make them look like this:
So basically the error message itself JSX code is:
<small style={{color: '#ea0027',marginBottom: '0.5rem',fontWeight: 'bold',}}>
<li style={{ listStyleType: 'circle' }}>{name} {error}</li>
</small>
And this is how I render the messages now:
{Object.entries(this.state.errors).map(([name, error]) => (
<small style={{color: '#ea0027',marginBottom: '0.5rem',fontWeight: 'bold'}}>
<li style={{ listStyleType: 'circle' }}>{name} {error}</li>
</small>
))}

maybe somthing like this. i dont know how the data in this.state.error looks so maybe you can select it out of error like in this example
{Object.entries(this.state.errors).map(([name, error]) => (
return (
<>
<li style={{ listStyleType: "circle" }}>
<RegisterInput
type="text"
invalid={true}
name="username"
value={this.state.username}
placeholder="Choose a username"
autoComplete="new-username"
onChange={(e) => this.onChange(e)}
pattern="^(?=[a-zA-Z0-9._]{3,20}$)(?!.*[_.]{2})[^_.].*[^_.]$"
/>
{error.username}
</li>
<li style={{ listStyleType: "circle" }}>
<RegisterInput
type="email"
name="email"
value={this.state.email}
autoComplete="new-email"
placeholder="Enter your email address"
onChange={(e) => this.onChange(e)}
/>
{error.email}
</li>
<li style={{ listStyleType: "circle" }}>
<RegisterInput
type="password"
name="password"
value={this.state.password}
placeholder="Password"
autoComplete="new-password"
onChange={(e) => this.onChange(e)}
/>
{error.password}
</li>
<li style={{ listStyleType: "circle" }}>
<RegisterInput
type="password"
name="re_password"
value={this.state.re_password}
placeholder="Confirm password"
autoComplete="new-re-password"
onChange={(e) => this.onChange(e)}
/>
{error.re_password}
</li>
</>
)
))}

Related

Uncaught TypeError: path.split is not a function while using react hook forms and material ui

consider the following block of code:
<TextField name="name" required className='my-2 mx-auto' label="Full Name" variant="standard" style={{ "width": "60%" }} value={name} onChange={(event) => { setName(event.target.value); }} {...register({
required: "Name is required"
})} />
I have replaced the ref with ...register but I am still getting the error, can someone please help me fix it?
No you can't do this because TextField is not only an input.
I think you have to pass {...register({ required: "Name is required"})} to the TextField's input and to do that, you could use TextField's inputProps prop. Something like:
<TextField
name="name"
required
className='my-2 mx-auto'
label="Full Name"
variant="standard"
style={{ "width": "60%" }}
value={name}
onChange={(event) => { setName(event.target.value); }}
inputProps={{...register({required: "Name is required"})}}
/>

Selecting an option from a dropdown list causes react app to crash

I have a react component that is a select/ option that is populated from state. When the app renders for the first time, the dropdown list populates correctly, but when I select one of the options the app crashes and I get the error 'values.appOwner.map() is not a function. I am looking to populate this form and send it to my backend server. I want to pass the selected corporation to the backend. Here is my code.
import React from 'react';
import Link from 'next/link';
import { useRouter } from 'next/router';
import { Image, Button, Badge } from 'antd';
const MobileAppCreateForm = ({
handleSubmit,
handleImage,
handleChange,
values,
preview,
uploadButtonText,
handleImageRemove
}) => {
const router = useRouter();
return (
<form className='add-content-form' onSubmit={handleSubmit}>
<div class='input-group'>
<input
type='text'
className='form-control'
placeholder='Mobile App Name'
name='appName'
value={values.appName}
onChange={handleChange}
style={{ marginRight: '.5rem' }}
/>
<select
title='Select Corporation'
name='appOwner'
className='form-select'
value={values.appOwner}
onChange={handleChange}
>
<option selected>Select a Corporation</option>
{values.appOwner &&
values.appOwner.map(corp => (
<option key={corp.corporationId} value={corp.corporationName}>
{corp.corporationName}
</option>
))}
</select>
<span
class='input-group-text ant-btn-primary'
style={{ cursor: 'pointer' }}
onClick={e => router.push('/add_content/add_corporation')}
>
Add Corporation
</span>
</div>
<div className='mb-3 mt-3'>
<textarea
className='form-control'
rows='4'
placeholder='Enter Mobile App Description'
name='appDescription'
value={values.appDescription}
onChange={handleChange}
/>
</div>
<div className='row'>
<div className='col-md-6'>
<input
type='text'
className='form-control'
placeholder='Mobile App Website'
name='appWebsite'
value={values.appWebsite}
onChange={handleChange}
/>
</div>
<div className='col-md-6'>
<input
type='text'
className='form-control'
placeholder='Mobile App Privacy Policy Link'
name='appPrivacyPolicyLink'
value={values.appPrivacyPolicyLink}
onChange={handleChange}
/>
</div>
</div>
<div className='row mt-3'>
<div className='col-md-4'>
<select
className='form-select'
name='appUserAccountDownload'
onChange={handleChange}
value={values.appUserAccountDownload}
>
<option selected disabled>
User Account Download
</option>
<option value='true'>True</option>
<option value='false'>False</option>
</select>
</div>
<div className='col-md-4'>
<select
className='form-select'
onChange={handleChange}
name='appLocationHistory'
value={values.appLocationHistory}
>
<option selected disabled>
User Location History
</option>
<option value='true'>True</option>
<option value='false'>False</option>
</select>
</div>
<div className='col-md-4'>
<input
type='text'
className='form-control'
placeholder='Mobile App Data Retention Length'
name='appDataRetention'
value={values.appDataRetention}
onChange={handleChange}
/>
</div>
</div>
<div className='row mt-3'>
<div className='col-md-12'>
<div className='form-group d-grid gap-2'>
<label className='btn btn-outline-secondary btn-block text-start'>
{uploadButtonText}
<input
type='file'
name='image'
onChange={handleImage}
accept='image/*'
hidden
/>
</label>
{preview && (
<div style={{ position: 'relative' }}>
<Badge
count='X'
onClick={handleImageRemove}
style={{
cursor: 'pointer',
position: 'absolute',
top: '5px',
right: '2px'
}}
>
<Image width={200} src={preview} />
</Badge>
</div>
)}
</div>
</div>
</div>
<div className='mb-3 mt-3'>
<textarea
className='form-control'
rows='4'
placeholder='iOS Associated Files'
name='appIosAssociatedFiles'
value={values.appIosAssociatedFiles}
onChange={handleChange}
/>
</div>
<div className='mb-3 mt-3'>
<textarea
className='form-control'
rows='4'
placeholder='iOS Associated Files'
name='appAndroidAssociatedFiles'
value={values.appAndoridAssociatedFiles}
onChange={handleChange}
/>
</div>
<Button
type='submit'
className='btn btn-primary ant-btn-primary'
onClick={handleSubmit}
disabled={values.loading || values.uploading}
loading={values.loading}
shape='round'
>
{values.loading ? 'Saving...' : 'Save'}
</Button>
<Button
type='submit'
className='btn btn-primary ant-btn-primary'
disabled={values.loading || values.uploading}
loading={values.loading}
shape='round'
style={{ marginLeft: '.25rem' }}
>
{values.loading ? 'Publishing...' : 'Publish'}
</Button>
</form>
);
};
export default MobileAppCreateForm;
Here is my handleChange method:
const handleChange = (e, index) => {
setValues({ ...values, [e.target.name]: e.target.value });
};
It seems that values.appOwner is not an array so you can't call map() on it. You could check if appOwner is actually and array instead of just checking if it's truthy ({values.appOwner && ...) since this condition would pass for a simple string or number and then would crash when calling map on it. You can use Array.isArray() to instead. You should still try to debug and see what's the actual value of values.appOwner to see why is not returning an array.
Edit after adding handleChange function code
The problem is with the handleChange method and also with the way you are handling state. You should use different objects to store the selected value and the initial options for the select. If you look at your code you are using values.appOwner both as the value prop in the select tag and as an array to iterate in to build the options. Once an option is selected you update appOwner with the selected value so it stops being an array.
Something like this could work
const [corporation, setCorporation] = useState('');
....
<select
title='Select Corporation'
name='appOwner'
className='form-select'
value={corporation}
onChange={event => setCorporation(event.target.value)}
You might want to store the selected corporation in the parent component instead but the important thing here is that is separated from the values.appOwner piece

React input value doesnt work with states

I have weird error. When i try change my input value with a state its not working but if i write my state some void place so its start changing value. Why its being like that ? My codes :
<Form
className="mt-4"
layout="vertical"
requiredMark="hidden"
name="basic"
form={form}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
>
<Form.Item
name="Name"
label="Başlık"
style={{ width: 400 }}
rules={[{ required: true, message: "Lütfen Başlık Giriniz!" }]}
>
<Input
id="IDTitle"
placeholder="Başlık"
onChange={handleInputChange}
/>
</Form.Item>
<Form.Item name="Url" label="URL" style={{ width: 400 }}>
{titleData} // if i write it its working. But if i delete that row its not shows or update value.
<Input placeholder="Url" disabled value={titleData}></Input>
</Form.Item>
<Button
type="primary"
className="submitButton float-right"
htmlType="submit"
>
Submit
</Button>
</Form.Item>
</Form>
const handleInputChange = (e) => {
const data = e.target.value;
console.log(data);
setTitleData(toEnglishChar(data));
};
How can i solve it ? Thanks for all replies! I dont know why its happening like that but i tried everything i can do. I tried change antd input with default input too but it didnt work too. Thanks for all replies !!
Change onChange event like the following:
<Input
id="IDTitle"
placeholder="Başlık"
onChange={e => handleInputChange(e)}
/>

Styled Component For Forms

I am using this form with material-ui components. Instead of writing the inline style that I am currently using for width, I wanted to opt for css-in-js. I have used styled-components previously but I don't think there's a form element with that.
The only example I came across was one where they had used built-in styled component labels. Since I have implemented validation on these material ui text fields as well so I don't want to change the structure. What would be the suitable way to put the style in css-in-js. I would prefer if there's a solution with styled-components.
return (
<div className="main-content">
<form
style={{ width: '100%' }}
onSubmit={e => {
e.preventDefault();
submitForm(email);
}}>
<div>
<TextField
variant="outlined"
margin="normal"
id="email"
name="email"
helperText={touched.email ? errors.email : ''}
error={touched.email && Boolean(errors.email)}
label="Email"
value={email}
onChange={change.bind(null, 'email')}
/>
<CustomButton
disabled={!isValid || !email}
text={'Remove User'}
/>
</div>
</form>
</div>
);
just make the styled form:
import styled from 'styled-components';
const Form = styled.form`
width: 100%;
`;
and use it:
return (
<div className="main-content">
<Form
onSubmit={e => {
e.preventDefault();
submitForm(email);
}}>
<div>
<TextField
variant="outlined"
margin="normal"
id="email"
name="email"
helperText={touched.email ? errors.email : ''}
error={touched.email && Boolean(errors.email)}
label="Email"
value={email}
onChange={change.bind(null, 'email')}
/>
<CustomButton
disabled={!isValid || !email}
text={'Remove User'}
/>
</div>
</Form>
</div>
);

How to automatically get and send User's geolocation values as a POST request to the backend

I'm a junior front-end developer building a react web form with formik that automatically gets the user's location and sends it as a post request to the back end. I've been able to use the geolocation API to get the latitude and longitude of the user, but don't know how to pass it as an object and a post request.
This is for an e-commerce website that provides the user different services based on businesses nearby.
class DriverForm extends Component {
constructor() {
super();
this.state = {
ready: false,
where: { lat: null, lng: null },
error: null
};
}
componentDidMount() {
//automatic location finder code goes here
const geoOptions = {
enableHighAccuracy: true,
timeOut: 20000,
maximumAge: 60 * 60 * 24
};
this.setState({ ready: false, error: null });
navigator.geolocation.getCurrentPosition(
this.geoSuccess,
this.geoFailure,
geoOptions
);
}
geoSuccess = position => {
console.log(position.coords.latitude, position.coords.longitude);
this.setState({
ready: true,
where: { lat: position.coords.latitude, lng: position.coords.longitude }
});
};
geoFailure = err => {
this.setState({ error: err.message });
};
render() {
return (
<>
<div id="map" />
<div className="form-position">
<h1 className="signupHeader">Driver Sign up</h1>
<Formik
initialValues={{
firstName: "",
lastName: "",
email: "",
phone: "",
password: "",
}}
validationSchema={DriverSchema}
onSubmit={values => alert(JSON.stringify(values, null, 2))}
>
{({
handleSubmit,
handleChange,
handleBlur,
values,
setFieldValue,
isSubmitting,
handleReset
}) => (
<Form>
<div className="name-field-position">
<br />
<ErrorMessage
className="error"
name="firstName"
component="span"
style={{ color: "red" }}
/>
<Field
name="firstName"
type="text"
className="inner-field-spacing field-display"
placeholder="Your First Name"
style={{ textAlign: "center", color: "purple" }}
id="firstName"
onChange={handleChange}
onBlur={handleBlur}
value={values.name}
/>
<br />
<ErrorMessage
className="error"
name="lastName"
component="span"
style={{ color: "red" }}
/>
<Field
name="lastName"
type="text"
className="inner-field-spacing field-display"
placeholder="Your Last Name"
style={{ textAlign: "center", color: "purple" }}
id="lastName"
onChange={handleChange}
onBlur={handleBlur}
value={values.name}
/>
</div>
<br />
<ErrorMessage
className="error"
name="email"
component="span"
style={{ color: "red" }}
/>
<Field
name="email"
type="email"
className="inner-field-spacing field-display"
placeholder="janedoe#email.com"
style={{ textAlign: "center", color: "purple" }}
id="email"
onChange={handleChange}
onBlur={handleBlur}
value={values.name}
/>
<br />
<ErrorMessage
className="error"
name="password"
component="span"
style={{ color: "red" }}
/>
<Field
name="password"
type="password"
className="inner-field-spacing field-display"
placeholder="password"
style={{ textAlign: "center", color: "purple" }}
onChange={handleChange}
onBlur={handleBlur}
value={values.name}
/>
......
<a href="/" className="button-flex">
<button
className="registerButton2"
type="submit"
disabled={isSubmitting}
>
Become A Driver
</button>
</a>
</Form>
)}
</Formik>
</div>
</>
);
}
}
export default DriverForm;
inside your onSubmit props send a post request using fetch or I personally prefer axios to your backend URL:
onSubmit{values => {
const request = axios.post({url, values})
request.then("handle your response in here")
}}

Categories

Resources