Form validation and error messages not working - reactjs

I'm currently working on several forms for an app and chose to use Material UI and React Hook Forms to build them. The basic functions are working, which means I can only proceed when all required inputs are filled and I'm getting the desired data.
Unfortunately I'm not able to use the form validation or display of error messages that comes with React Hook Form. It is still using the Material UI validation, even though I followed along to the documentation as close as possible.
Here's what I want to be able to do:
define the min and max length of an input
enter RegEx patterns for password inputs
show the neat looking error messages of React Hook Form
Some of the logic is working, some is not. Can you help me figure out why? Thank you in advance!
import React from 'react';
import { useForm, Controller } from 'react-hook-form';
import { Link } from 'react-router-dom';
// COMPONENTS
import Button from '../01-atoms/inputs/Button';
import Textfield from '../01-atoms/inputs/Textfield';
// MATERIAL UI - CORE
import Fade from '#material-ui/core/Fade';
import Grid from '#material-ui/core/Grid';
import InputAdornment from '#material-ui/core/InputAdornment';
import Typography from '#material-ui/core/Typography';
import Paper from '#material-ui/core/Paper';
// MATERIAL UI - ICONS
import LockSharpIcon from '#material-ui/icons/LockSharp';
import PersonAddSharpIcon from '#material-ui/icons/PersonAddSharp';
export default function SignUp({ i18n, submitSignUpData }) {
const { register, handleSubmit, control, errors } = useForm();
return (
<Grid item xs={12} sm={6} md={3}>
<Fade in>
<Paper elevation={3}>
<Typography align='center' gutterBottom variant='h5'>
{i18n.sign_up.page_title}
</Typography>
<form onSubmit={handleSubmit(submitSignUpData)}>
<Grid container spacing={1}>
<Grid item xs={12}>
<Controller
// This is not working:
rules={register({
required: true,
minLength: 8,
})}
// But this is:
required
as={Textfield}
name='newPassword'
control={control}
defaultValue=''
fullWidth
label={i18n.login.password_placeholder}
variant='outlined'
type='password'
InputProps={{
endAdornment: (
<InputAdornment position='end'>
<LockSharpIcon />
</InputAdornment>
),
}}
/>
{errors.newPassword && 'Your input is required!'}
</Grid>
<Grid item xs={12}>
<Button
fullWidth
content={i18n.sign_up.get_started_button}
variant='contained'
color='secondary'
type='submit'
endIcon={<PersonAddSharpIcon />}
/>
</Grid>
</Grid>
</form>
<Link to='/log-in'>
<Typography>{i18n.login.login_button}</Typography>
</Link>
</Paper>
</Fade>
</Grid>
);
}

Instead of using controller why don't you use TextField of Material UI. I have something like this in my code.
<TextField
name="newPassword"
label="Password"
inputRef={register({ required: true, minLength: 8 })}
defaultValue=''
/>
{
errors.newPassword &&
<ErrorText>
{errors.newPassword.type === "required" ?
'Password is required.' :
`Min character limit for Password is 8.`}
</ErrorText>
}

Related

Remove the border from TexfField

I started using #Mui for React and I used it to create the form but after I focused TextField I see the border linke on the below screen:
My code look like this:
<FormGroup>
<TextField
label="Description"
name="description"
multiline
rows={5}
fullWidth
value={data.description}
variant="standard"
onChange={onHandleChange}
/>
</FormGroup>
How remove that?
#Edit
I resolved my problem. Border around of this element appears becouse I has styles from Breeze
Normally this can be done via CSS as well.
input {
outline: none
}
You can change the styling (remove the underline) of TextField when it is focused with makeStyles using :after
In your case do the following :
import TextField from "#mui/material/TextField";
import FormGroup from "#mui/material/FormGroup";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles({
underline: {
"&&:after": {
borderBottom: "none"
}
}
});
export default function ComboBox() {
const classes = useStyles();
return (
<FormGroup>
<TextField
InputProps={{ classes }}
label="Description"
name="description"
multiline
rows={5}
fullWidth
value={data.description}
variant="standard"
onChange={onHandleChange}
/>
</FormGroup>
);
}
And if you want it with no border at all you can pass InputProps={{ disableUnderline: true }} to your TextField

Textfield's label gets clipped when inside a Dialog

When using a Textfield as the first child of DialogContent:
export default function App() {
return (
<Dialog open={true}>
<DialogTitle>Hey</DialogTitle>
<DialogContent>
<TextField
fullWidth
id='name'
label={'Foo'}
name='name'
required
type='text'
value={'Bar'}
/>
</DialogContent>
</Dialog>
);
}
its label (when using `variant="outlined") gets clipped. See codebox sample. Any way to fix this problem? e.g. by customizing the theme?
You can easily fix that issue by adding some margin to the TextField like the following.
sx={{ marginTop: 2 }}
Or you could wrap the TextField using Box inside the DialogContent like the following.
<Box p={1}>
<TextField
...
/>
</Box>

Can't get TreeView Icons and IconButton for Tests

I'm trying to test a component that has an endAdornment IconButton and other with a TreeView, but neither the IconButton and the ExpandIcon/CollapseIcon have good options to dispatch test events.
This is the TextField component that I'm using:
<TextField
fullWidth
label="Label"
onChange={handleChange}
type="text"
InputProps={{
endAdornment: (
<InputAdornment >
<IconButton onClick={openAssetHierarchy}>
<Folder />
</IconButton>
</InputAdornment>
),
}}
/>
This is the TreeView component:
<TreeView
defaultCollapseIcon={<ArrowDropDown />}
defaultExpandIcon={<ArrowRight />}
defaultEndIcon={<div style={{ width: 24 }} />}
onNodeToggle={handleToggle}
onNodeSelect={handleSelect}
>
[...]
</TreeView>
For the TextField icon button:
For TreeView when using Testing Playground to get the icon
There aren't good queries to get the icons for tests. How can I get these options?
For the IconButton you can add an aria-label attribute to the element, then use getByLabelText to access it in your test. This is also useful and recommended for accessibility purposes.
<IconButton aria-label="add a file" onClick={openAssetHierarchy}>
<Folder />
</IconButton>
screen.getByLabelText('add a file') // Gets you the `IconButton`
For the TreeView items, I assume you don't actually need to access the icon specifically but simply need to access the TreeItem for testing purposes. This can be done with getByRole and passing the tree item's name.
screen.getByRole('treeitem', { name: /Test1/ }) // Gets you the first `TreeItem`

How to validate material-ui select with Formik and Yup

I just started with Yup and Formik. I have a pretty basic form. The TextFields that I have are working just fine in terms of validation with Yup. The select is what I am having trouble with. I've been trying to get it to be required just like my text fields. I have been googling for awhile but I haven't found anything that has helped thus far.
I tried making my own validation that happened onBlur and that worked, but when it came to just trying to save without filling any values in it failed. The text fields would show required, but the select wouldn't show anything. You could fill out the text fields and try to save again. Doing that would show the required message for the select now because it could submit. From what I can tell formik's submit doesn't happen until all the Yup required fields are good to go. I will post what I am trying below, any help would be appreciated.
If I comment out the Yup validation requirements and log out the values on submit, the selected value does show up, so that seems to be working at least. Just can't figure out how to validate it.
import React, { useEffect, useState } from "react";
import Button from '#material-ui/core/Button'
import Grid from '#material-ui/core/Grid'
import { TextField, Select } from "formik-material-ui";
import { Formik, Form, Field } from "formik";
import * as Yup from "yup";
import MenuItem from "#material-ui/core/MenuItem"
const Validation = Yup.object().shape({
FirstName: Yup.string().required("Required"),
LastName: Yup.string().required("Required"),
Gender: Yup.string().required("Required"),
});
<Formik
onSubmit={(values) => {
SaveSettings(values)
}}
enableReinitialize
validateOnChange={false}
initialValues={data}
validationSchema={Validation}
>
{({ submitForm, handleChange }) => (
<Form>
<Field
component={Select}
name="Gender"
variant="outlined"
label="Gender"
className={classes.formControl}
onChange={e => handleChange(e)} >
<MenuItem value="Male">Male</MenuItem>
<MenuItem value="Female">Female</MenuItem>
</Field>
<Grid item>
<Field
disabled={false}
component={TextField}
data-id="FirstName"
variant="outlined"
label="First Name"
className={classes.formControl}
name="FirstName" />
</Grid>
<Grid item>
<Field
disabled={false}
component={TextField}
data-id="LastName"
variant="outlined"
label="Last Name"
className={classes.formControl}
name="LastName" />
</Grid>
<Grid item>
<Button type="button" variant="contained" onClick={submitForm}>Save settings</Button>
</Grid>
</Form>
)}
</Formik>

Material-UI checkboxes and radio buttons look so ugly

Hi! I was making a form using Formik in React (class-based component) and I got very ugly looking checkboxes and radio buttons. I have tried to dig-into the code using inspect element in Chrome, but still couldn't solve it. I have uploaded here the picture as well. I have used the same checkboxes in Angular from the same source, but works fine there. I don't know why it is not working in React.
The Material-UI is installed in package.json file as a dependency:
"#material-ui/core": "^4.11.0"
Here is how I have written the code:
import React, { Component } from 'react';
import { Formik } from 'formik';
import { FormControlLabel, FormControl, FormLabel, Checkbox, Select, MenuItem, Radio, RadioGroup } from '#material-ui/core';
export default class FormikForm extends Component {
componentDidMount() {}
render() {
return (
<div className="formik-container">
<Formik>
<form>
<FormControlLabel
className="paper-checkbox col-md-12"
control={
<Checkbox
onChange={handleChange}
onBlur={handleBlur}
value="markAllDay"
color="secondary"
name="markAllDay"
/>
}
label="Book for the whole day"
/>
<FormControlLabel
className="paper-checkbox col-md-12"
control={
<Checkbox
onChange={handleChange}
onBlur={handleBlur}
value="markRecurring"
color="secondary"
name="markRecurring"
/>
}
label="Recurring event"
/>
<FormControl component="fieldset">
<RadioGroup
row aria-label="eventType"
name="recurEventType"
onChange={handleChange}
>
<FormControlLabel
value="recur"
control={<Radio />}
label="Whole recur event"
/>
<FormControlLabel
value="event"
control={<Radio />}
label="Only this event"
/>
</RadioGroup>
</FormControl>
</form>
</Formik>
</div>
);
}
}
<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>

Resources