I'm trying to add simple custom validation (non-empty or minimum characters) to a MUI TextField that is part of React functional component using the Formik useField hook. This reusable component will be a part of Formik form in it's parent component. The use of this functional child component is for it to be a reusable component and so the validation for the Textfield should occur within the component instead of the ValidationScheme attribute in the parent component's Formik tag since the form is not predefined. How can I add this custom validation to the TextField within the child component?
import React from 'react';
import { useField } from "formik";
import { TextField, TextFieldProps } from '#material-ui/core';
type FormikTextFieldProps = {
formikKey: string,
} & TextFieldProps
const FormikTextField = ({ formikKey, ...props }: FormikTextFieldProps) => {
const [field, meta, helpers] = useField(formikKey);
const validate = () => {
if(!field.value){
helpers.setError('The field is empty')
}
}
return (
<>
<TextField
id={field.name}
name={field.name}
helperText={meta.touched ? meta.error : ""}
error={meta.touched && Boolean(meta.error)}
value={field.value}
onChange={field.onChange}
{...props}
/>
{meta.touched && meta.error ? (
<div className="error">{meta.error}</div>
) : null}
</>
)
}
export default FormikTextField
Related
React DateTimePicker is showing required error even after selecting a value in DatePicker:
const validationForm = Yup.object().shape({
DateTime:Yup.date().required('Date and time is required')
});
<DateTimePicker {...register('DateTime')}/>
Here the register function from react form hook form might not support the 3rd party library react datetimepicker.
For these types of components, we can use the Control component from react hook form to wrap the custom component for the validations.
For ex.
import React from "react";
import ReactDatePicker from "react-datepicker";
import { TextField } from "#material-ui/core";
import { useForm, Controller } from "react-hook-form";
function App() {
const { handleSubmit, control } = useForm();
return (
<form onSubmit={handleSubmit(data => console.log(data))}>
<Controller
control={control}
name="ReactDatepicker"
render={({ field: { onChange, onBlur, value, ref } }) => (
<ReactDatePicker
onChange={onChange}
onBlur={onBlur}
selected={value}
/>
)}
/>
<input type="submit" />
</form>
);
}
For more information refer to the official docs from react hook form.
React Hook form Control
I am working with react and react-bootstrap and react-select.
I have one issue, when I clicked the button its like not showing on console and not do any action.
The Input.js functional component is a child of Hero.js functional component.
So the hero.js is the parent component and Input.js is a child component.
And my button is in Parent component(Hero.js).
So I am using the forwarding ref to parent to child component on my button handler.
I am using react-select input in Input.js and I want to focus when button is clicked.
The console is also not showing on button clicked.
here is Hero.js (Parent component)
import React, { useState} from "react";
import "../App.css";
import Input from "./Input";
import Btnfill from "./Btnfill";
function Hero() {
const [Infocus, setInfocus] = useState();
const focusInput = () => {
console.log(Infocus.current);
Infocus.focus();
}
return (
<>
<Input
icon={Search}
cname={{ iconavailable: "input", noIcon: "input-notIcon" }}
placeholder="Search Industries"
ref={setInfocus}
/>
<Btnfill text="Search" size="larger" onClick={focusInput} />
</>
);
}
export default Hero;
Here is Input.js
import React, { useState, useEffect} from "react";
import Select from "react-select";
const Input = React.forwardRef((props, refrence) => {
// Input select options
const options = [
{ value: "chocolate", label: "Chocolate" },
{ value: "strawberry", label: "Strawberry" },
{ value: "vanilla", label: "Vanilla" },
];
return (
<div>
<Select
defaultValue={selectedOption}
onChange={onChangeEvent}
options={options}
className={props.icon ? props.cname.iconavailable : props.cname.noIcon}
placeholder={props.placeholder}
ref={refrence}
/>
</div>
);
})
export default Input;
You want to use ref, but what you actually do in your Hero.js is - you are defining state and pass down the set-state function down.
What you instead need to do:
Define new ref in Hero.jsx: const inputRef = useRef();
In your on button click handler set the focus. To do so, you need to access the current property of the ref: const focusInput = () => inputRef.current.focus();
Pass down ref instead: <Input ... ref={inputRef} />
https://codesandbox.io/s/nervous-lewin-8510tf
I am new to react and i ran into this error while creating a custom form control, does anyone know why this is happening and how to solve it?
error:
Warning: A component is changing a controlled input to be uncontrolled. This is likely caused by the value changing from a defined to undefined, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info:
code:
import React from "react";
import { TextField, Grid } from "#material-ui/core";
import { useFormContext, Controller } from "react-hook-form";
const FormInput = ({ name, label, required }) => {
const { control } = useFormContext();
return (
<Grid item xs={12} sm={6}>
<Controller
render={({ field }) => (
<TextField fullWidth label={label} required={required} {...field} />
)}
control={control}
name={name}
/>
</Grid>
);
};
export default FormInput;
I created a DateTimePicker component for my react-admin project:
import { DateTimePicker, DateTimePickerProps, MuiPickersUtilsProvider } from "#material-ui/pickers";
import { FC } from "react";
import { FieldTitle, InputProps, useInput } from "react-admin";
import MomentUtils from "#date-io/moment";
import moment from "moment";
import "moment/locale/fr";
interface DateTimeInputProps extends InputProps<DateTimePickerProps> {
label: string;
}
export const DateTimeInput: FC<DateTimeInputProps> = ({ source, label, resource, options }) => {
const {
input: { value, onChange },
isRequired,
} = useInput({ source });
return (
<MuiPickersUtilsProvider
libInstance={moment}
utils={MomentUtils}
locale='fr'
>
<DateTimePicker
label={<FieldTitle
label={label}
source={source}
resource={resource}
isRequired={isRequired}
/>}
value={value || null}
onChange={onChange}
format="llll"
ampm={false}
{...options}
/>
</MuiPickersUtilsProvider>
);
}
It works great, however the design does not follow the other classic inputs:
What is the simplest way to keep the same design across custom material-ui components?
There are 3 variants to choose from that are applied to MUI input elements: outlined, filled and standard. You need to provide DateTimePicker with inputVariant prop set to filled to get a "greyish" look. Plus you need to pass a className prop so that react-admin can pass parent controled classses (this should fix width issues).
<DateTimePicker {...props} inputVariant="filled" className={props.className} />
You can see the look of outlined, filled and standard clicking link below:
https://mui.com/components/text-fields/#basic-textfield
I'm using the material ui library, and in the onBlur input event I'm adding 2 events, one that is coming by props and another is declared in the same component.
onBlur={(props.onBlur, validation)}
but he only recognizes me for the second event that happened to him.
It is not recognizing me the two events that are in onBlur.
import React, { useState } from "react";
import FormControl from "#material-ui/core/FormControl";
import FormHelperText from "#material-ui/core/FormHelperText";
import Input from "#material-ui/core/Input";
import InputLabel from "#material-ui/core/InputLabel";
export default function CustomInputExample(props) {
const [validationValue, setValidation] = useState(false);
const validation = () => {
if (props.value === "") setValidation(true);
else setValidation(false);
};
return (
<FormControl>
<InputLabel htmlFor={props.name}>{props.labelText}</InputLabel>
<Input
name={props.name}
aria-describedby="component-helper-text"
type="text"
onChange={props.onChange}
onBlur={(props.onBlur, validation)}
value={props.value}
/>
{props.required !== undefined && validationValue ? (
<FormHelperText id={props.name}>Required field</FormHelperText>
) : null}
</FormControl>
);
}
I need to use those two events in onBlur.
You can call 2 function using an anonymous function,
onBlur={() => {
props.onBlur();
validation();
}}