Formik form not rendering - reactjs

Just setting up a basic bonehead form for learning purposes and ... can't seem to render. No errors. Functional component runs. Just nothing to see...
MyForm.tsx
export const MyForm: React.FC = () => {
console.log("MyForm has been called")
return (
<div>
<Formik initialValues={{ firstName: "roberto" }} onSubmit={data => { console.log(data) }}>
{({ values, handleChange, handleSubmit, handleBlur }) => {
<form onSubmit={handleSubmit}>
<TextField value={values.firstName} onChange={handleChange} onBlur={handleBlur} name="firstName" />
<pre>JSON.stringify(values)</pre>
</form>
}}
</Formik>
</div >
)
}
I've imported MyForm properly into App.tsx, and MyForm is currently all I'm returning from App.tsx.
No errors. Just nothin...

I don't think you're returning your form which is why it's not rendering:
export const MyForm: React.FC = () => {
console.log("MyForm has been called")
return (
<div>
<Formik initialValues={{ firstName: "roberto" }} onSubmit={data => { console.log(data) }}>
{({ values, handleChange, handleSubmit, handleBlur }) => (
<form onSubmit={handleSubmit}>
<TextField value={values.firstName} onChange={handleChange} onBlur={handleBlur} name="firstName" />
<pre>JSON.stringify(values)</pre>
</form>
)}
</Formik>
</div >
)
}
Note that I changed the function's curly braces to parens around your <form>. Alternatively, you could leave the curly braces and instead
{({ values, handleChange, handleSubmit, handleBlur }) => {
return (<form>...</form>)
}}

Related

TypeError: Cannot read property 'setFieldValue' of undefined. Formik doesn't recognise setFieldValue

I'm trying to create an image upload on my form. The problem is when I try to change the value to the actual uploaded file. I am trying to use setFieldValue, but it says it is undefined. Below is the code. Any ideas why it is undefined? I thought it comes with Formik.
import { Formik } from 'formik';
const AddProduct = (props) => {
return (
<Formik
initialValues={{
serviceImage: null
}}
onSubmit={(values) => {
console.log(values);
}}
>
{({
errors,
handleBlur,
handleChange,
handleSubmit,
setFieldValue,
isSubmitting,
touched,
values,
formProps
}) => (
<form onSubmit={handleSubmit}>
<TextField
error={Boolean(touched.serviceName && errors.serviceName)}
fullWidth
helperText={touched.serviceName && errors.serviceName}
label="Service name"
margin="normal"
name="serviceName"
onBlur={handleBlur}
onChange={handleChange}
value={values.serviceName}
/>
<Button>
<input
id="file"
name="serviceImage"
value={values.serviceImage}
type="file"
onChange={(event) => formProps.setFieldValue('serviceImage', event.target)
}
/>
Add an Image
</Button>
<Button
type="submit" >
Post this service on the Events Platform
</Button>
</form>
)}
</Formik>
);
};
You already declare setFieldValue in your formik callback function
So change it to:
<input
id="file"
name="serviceImage"
value={values.serviceImage}
type="file"
onChange={event => setFieldValue('serviceImage', event.currentTarget.files[0])}
/>;

How can i pass render props to children in React functional components?

i am using react-final-form I have a Form Component something like this:
export function Form = ({ children, onSubmit, initialValues, ...props }) => {
return (
<FinalForm
initialValues={initialValues}
onSubmit={onSubmit}
render={({ handleSubmit, submitting, pristine, valid }) => (
<form onSubmit={handleSubmit} className="space-y-6" {...props}>
{children}
</form>
)}
/>
)
}
export default Form;
I want to use this form component like this:
<Form>
({ valid, pristine, submitting } => (
<TextInput name="email" label="Email Address" type="email" />
<Button text="Login" disabled={!valid || pristine || submitting} />
)
</Form>
How can i pass the props valid, pristine and submitting to my childs so i can use it for e.g. disable a Button?
Instead of
{children}
Try this,
{
React.Children.map(children, child => {
if (React.isValidElement(child)) {
return React.cloneElement(child, { submitting, pristine, valid });
}
return child;
});
}

How to use Formik with input names that have dots "."?

I'm unable to get handleChange to update an input with dots "." in the name. Has anyone solved this?
<Formik component={({
handleSubmit,
handleChange,
handleBlur,
values,
errors,
}) => (
<form onSubmit={handleSubmit}>
<input
type="text"
onChange={handleChange}
onBlur={handleBlur}
value={values['name.of.input']}
name="name.of.input"
/>
{errors['name.of.input'] && <div>{errors['name.of.input']}</div>}
<button type="submit">Submit</button>
</form>
)} />;
Edit: Here is the refactored version that works
<Formik component={({
initialValues={{
name: {
of: {
input: ''
}
}
}},
handleSubmit,
handleChange,
handleBlur,
values,
errors,
}) => (
<form onSubmit={handleSubmit}>
<input
type="text"
onChange={handleChange}
onBlur={handleBlur}
value={values.name.of.input}
name="name.of.input"
/>
{getIn(errors, 'name.of.input') && <div>getIn(errors, 'name.of.input')</div>}
<button type="submit">Submit</button>
</form>
)} />;
You should use getIn and you can see an examples in the docs here and here.
const inputValue = getIn(values, 'name.of.input')
const inputError = getIn(errors, 'name.of.input')
const inputTouched = getIn(touched, 'name.of.input')
name.of.input means your Formik state should have shape something like this:
{
name: {
of: {
input: ''
}
}
}
Now the values you're getting from Formik will also have the same shape, so to access value off of values you need do this:
values={values.name.of.input}

How do I access current value of a formik field without submitting?

How do I access value of the SelectField named countryCode in my React component? Use case is that validation scheme should change according to the countryCode.
<Formik
onSubmit={(values, actions) => this.onSubmit(values, actions.setFieldError)}
validationSchema={() => this.registrationValidationSchema()}
enableReinitialize={true}
initialValues={this.props.initialData}
>
<Form>
<Field
name="countryCode"
component={SelectField}
label="Country"
labelClassName="required"
options={Object.entries(sortedCountryList).map(x => ({
value: x[1][1],
label: x[1][0]
}))}
/>
</Form>
</Formik>
I have tried to access it via a ref, then via this.props.values (as suggested in getFieldValue or similar in Formik) but both return just undefined or null. My props don't have any "values" field.
EDIT: Found an ugly way: document.getElementsByName("countryCode")[0].value. A better way is appreciated.
You can use ref, if you need the values outside formik
const ref = useRef(null);
const someFuncton = () => {
console.log(ref.current.values)
}
<Formik
innerRef={ref}
onSubmit={(values, actions) => this.onSubmit(values,
actions.setFieldError)}
validationSchema={() => this.registrationValidationSchema()}
enableReinitialize={true}
initialValues={this.props.initialData}
/>
<form></form>
</Formik>
You can access values like this:
<Formik
onSubmit={(values, actions) => this.onSubmit(values,
actions.setFieldError)}
validationSchema={() => this.registrationValidationSchema()}
enableReinitialize={true}
initialValues={this.props.initialData}
>
{({
setFieldValue,
setFieldTouched,
values,
errors,
touched,
}) => (
<Form className="av-tooltip tooltip-label-right">
// here you can access to values
{this.outsideVariable = values.countryCode}
</Form>
)}
</Formik>
you can get it from formik using the Field comp as a wrapper
import React, { ReactNode } from 'react';
import { Field, FieldProps } from 'formik';
(...other stuffs)
const CustomField = ({
field,
form,
...props
}) => {
const currentError = form.errors[field.name];
const currentField = field.name; <------ THIS
const handleChange = (value) => {
const formattedDate = formatISODate(value);
form.setFieldValue(field.name, formattedDate, true);
};
const handleError = (error: ReactNode) => {
if (error !== currentError) {
form.setFieldError(field.name, `${error}`);
}
};
return (
<TextField
name={field.name}
value={field.value}
variant="outlined"
helperText={currentError || 'happy helper text here'}
error={Boolean(currentError)}
onError={handleError}
onChange={handleChange}
InputLabelProps={{
shrink: true,
}}
inputProps={{
'data-testid': `${field.name}-test`, <---- very helpful for testing
}}
{...props}
/>
</MuiPickersUtilsProvider>
);
};
export default function FormikTextField({ name, ...props }) {
return <Field variant="outlined" name={name} component={CustomField} fullWidth {...props} />;
}
it is very simple just do console.log(formik.values) and you will get all the values without submitting it.

React-bootstrap switch not displaying

I'm trying to incorporate Formik and React-bootstrap.
It's going as expected except the switch component.
Here is my function for rendering the switch:
function ReactSwitch(props){
return(
<>
<Col md={props.col}>
<Form.Group>
<Form.Check
type="switch"
id={props.id}
name={props.name}
label={props.label}
checked={props.checked}
onChange={props.onChange}
/>
</Form.Group>
</Col>
</>
);
}
And here is my initialization for Formik:
const formik = useFormik({
initialValues: {
wflow_switch: false
},
onSubmit: values => {
alert(JSON.stringify(values, null, 2));
},
});
Note that when I change the type from switch to checkbox, it displays a checkbox but still no label. What am I doing wrong? I'm still learning React so any comments are appreciated.
I guess you'll need to use state and enable enablereinitialize
Try this:
export default function FormSwitch() {
// add checked state
const [checked, setChecked] = useState(false)
const { handleSubmit, values } = useFormik({
initialValues: {
// initial value is set 'false' by state
switch: checked
},
// Control whether Formik should reset the form if initialValues changes
enableReinitialize: true,
onSubmit: (values, { setSubmitting }) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2))
setSubmitting(false)
}, 400)
}
})
return (
<form className="form" onSubmit={handleSubmit}>
<ReactSwitch
name="switch"
label="Switch"
id="switch"
checked={checked}
onChange={() => setChecked(!checked)}
/>
<button type="submit">
Submit
</button>
</form>
)
}
Edit: Different approach using useField with <Formik>
import { Formik, useField } from "formik"
import { Col, Form } from "react-bootstrap"
const ReactSwitch = ({ ...props }) => {
const [field, form] = useField(props)
return (
<Col md={props.col}>
<Form.Group>
<Form.Check
type="switch"
id={props.id}
checked={field.value.checked}
onChange={() => form.setFieldValue(props.name, !field.value)}
{...field}
{...props}
/>
</Form.Group>
</Col>
)
}
export default function Switch() {
return (
<Formik
initialValues={{
switch: false
}}
onSubmit={values => alert(JSON.stringify(values, null, 2))}
>
{formik => (
<form onSubmit={formik.handleSubmit}>
<ReactSwitch label="Switch" name="switch" id="switch" />
<button type="submit">submit</button>
</form>
)}
</Formik>
)
}

Resources