enzyme: find() formik components inside an anonymous function - reactjs

I am using enzyme for testing react components.
I have a formik form with this structure:
Form.js
export class Form extends Component {
constructor(props) {
//...
}
render() {
<Formik
inititalValues={{
//...
}}
onSubmit={(values, { resetForm }) => {
//...
//...
}}
onReset = {(values, formProps) => {
//...
}}
validationSchema={
//...
}>
{
(props) => {
const {values, errors, handleSubmit} = props;
return (
<form onSubmit={handleSubmit}>
<input type='text' name='email' />
<input type='password' name='password' />
<button type='submit'>Submit</button>
</form>
)
}
}
</Formik>
}
}
How do i use enzyme's find() method to get those input fileds?
I can get the main <Formik> component but can't get the input fields inside that anonymous function. Any help would be appriciated.

You can use dive() to expand the nested form.
shallow(<Form {...props} />)
.find(Formik)
.dive()
You can also trigger Formik props directly using prop(key)
shallow(<Form {...props} />)
.find(Formik)
.prop('onSubmit')(args)

Related

Input react wrapper

I want to make a form for user data and I was asked to make a wrapper react components for each type of input. My problem is passing the handler to the input component.
This is my form:
import React from 'react';
import {addUser as addNewUser} from '../../services/index';
import {TextBox} from './TextBox'
interface AddUserProps{
}
interface AddUserState{
UserName:string,
}
export default class AddUser extends React.Component<AddUserProps, AddUserState> {
constructor(props:any) {
super(props);
this.state = {
UserName: '',
};
this.updateUserName = this.updateUserName.bind(this);
}
updateUserName(event: React.ChangeEvent<HTMLInputElement>) {
this.setState({UserName: event.target.value});
}
handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
console.log(this.state)
addNewUser(this.state)
}
render() {
return (
<div>
<form
className = "user-add-form"
onSubmit={(event) => this.handleSubmit(event)}
>
<h3>Adauga utilizatori:</h3>
<label htmlFor="userName">User Name:</label>
<TextBox name="userName" type="text" value={userName} handleChange={this.updateUserName}/>
<input type="submit" value="Add user"/>
</form>
</div>
)
}
}
export {AddUser};
And this is the input component that I made:
import React from 'react'
export function TextBox(props) {
return (
<div>
<input type={props.type}
name={props.name}
value={props.value}
onChange={(event) => props.HandleInput(event)}
/>
</div>
)
}
So what I don't know is how to pass the event handler to the input component, because as it is right now it can't find it.
It should exist in Textbox's props as handleChange as it's passed in the parent component. Does this not work?
<input
type={props.type}
name={props.name}
value={props.value}
onChange={(event) => props.handleChange(event)}
/>

Submitting a Formik Form on Unmount

Is it possible to submit a Formik Form without having a submit button?
For example submitting the Form when the component unmounts so the user doesn't need to click a button to save.
Think of something like that:
import React from "react";
import { Formik, Form, Field } from "formik";
const Example = () => {
useEffect(() => {
return () => {
//trigger Submit or send Request with Form Values from here
};
}, []);
return (
<Formik
initialValues={{
firstName: "",
lastName: "",
}}
onSubmit={(values, { setSubmitting }) => {
//send Request
}}
>
{() => (
<Form>
<Field name="firstName" />
<Field name="lastName" />
</Form>
)}
</Formik>
);
};
export default Example;
You can create a functional component that auto-submits. By having it render inside the component, you have reference to the context of the form. You can use:
import { useFormikContext } from 'formik';
function AutoSubmitToken() {
// Grab values and submitForm from context
const { values, submitForm } = useFormikContext();
React.useEffect(() => {
return submitForm;
}, [submitForm]);
return null;
};
You can use it under the component as such
<Form>
<Field name="token" type="tel" />
<AutoSubmitToken />
</Form>
You can read all about it here

Use useRef to call submitForm from a parent component

I am using react hooks and useRef to call a child method from the parent (see here: Call child method from parent)
Specifically, I am trying to call the formik submitForm method which is located in my child component from my parent component. I know there are other ways to do this (React Formik use submitForm outside <Formik />) but i would really like to use useRef.
const Auth1 = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
handleSubmit() {
///////////formik submitForm function goes here
}
}));
return(
<div>
<Formik
initialValues={props.initValues}
validationSchema={Yup.object().shape({
name: Yup.string().required('Required'),
})}
onSubmit={(values, actions) => {
console.log(values)
}}
render={({ values }) => (
<Form>
<Field
name="name"
value={values.name}
component={TextField}
variant="outlined"
fullWidth
/>
</Form>
)}
/>
</div>
)
})
There must be a way to bind the submitForm function out of the component and into the body of my Auth1 component, but imnot quite too sure how.
Any help is greatlly appreciated, thanks!
You can pull the handleSubmit function out of the useImperativeHandle call the exposed method from parent using ref
const Auth1 = forwardRef((props, ref) => {
const handleSubmit = (values, actions) => {
///////////formik submitForm function goes here
}
useImperativeHandle(ref, () => ({
handleSubmit
}), []);
return(
<div>
<Formik
initialValues={props.initValues}
validationSchema={Yup.object().shape({
name: Yup.string().required('Required'),
})}
onSubmit={handleSubmit}
render={({ values }) => (
<Form>
<Field
name="name"
value={values.name}
component={TextField}
variant="outlined"
fullWidth
/>
</Form>
)}
/>
</div>
)
})
Now from the parent you could have
const Parent = () => {
const authRef = useRef(null);
...
const callSubmit = () => {
authRef.current.handleSubmit(values, actions);
}
return (
<>
{/* */}
<Auth1 ref={authRef} />
</>
)
}

React formik read input value outside <Formik/> in real time onchange

Here is the code https://codesandbox.io/s/5wmrp396kp
I have no idea how to read the value outside the .
I just need a very simple function to show the value in other component like the helper.js
class ComponentOne extends Component {
render() {
return (
<React.Fragment>
<div>CompoenntOne: I wannna read the props.values.email here</div>
<div>CompoenntOne: I wannna read the props.values.email2 here</div>
</React.Fragment>
);
}
}
Any way to made this work in simple?
Your code doesn't even have Formik components included.
Please, implement something like this basic example from docs:
import React from 'react';
import { Formik } from 'formik';
const BasicExample = () => (
<div>
<h1>My Form</h1>
<Formik
initialValues={{ name: 'jared' }}
onSubmit={(values, actions) => {
setTimeout(() => {
alert(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
}, 1000);
}}
render={props => (
<form onSubmit={props.handleSubmit}>
<input
type="text"
onChange={props.handleChange}
onBlur={props.handleBlur}
value={props.values.name}
name="name"
/>
{props.errors.name && <div id="feedback">{props.errors.name}</div>}
<button type="submit">Submit</button>
</form>
)}
/>
</div>
);

reactjs container component form values

I am new to react and am trying to get the value from the firstName input in handleSubmit. handleSubmit is working but for some reason the input value is undefined. I tried following some other examples but they were all forms in React components.
let SomeForm = (props) => {
let firstName = '';
const handleSubmit = (e) => {
e.preventDefault();
console.log(firstName);
}
return (
<div>
<form onSubmit={handleSubmit}>
<TextField
floatingLabelText="First Name"
floatingLabelFixed={true}
underlineStyle={styles.underlineStyle}
underlineFocusStyle={styles.underlineFocusStyle}
value={firstName}
/>
<input type="submit" value="Submit" />
</form>
</div>
)
}
SomeForm = connect()(SomeForm)
export default SomeForm
You need to add onChange to the TextField to handle the updates. And because SomeForm is a stateful component, you may need to use a class component instead of a stateless functional component.
class SomeForm extends React.Component {
state = {
firstName: ''
};
handleChange = (e, value) => {
this.setState({ firstName: value });
};
handleSubmit = (e) => {
e.preventDefault();
console.log(this.state.firstName);
};
render () {
return (
<div>
<form onSubmit={this.handleSubmit}>
<TextField
id="text-field-controlled"
floatingLabelText="First Name"
floatingLabelFixed={true}
underlineStyle={styles.underlineStyle}
underlineFocusStyle={styles.underlineFocusStyle}
value={this.state.firstName}
onChange={this.handleChange}
/>
<input type="submit" value="Submit" />
</form>
</div>
)
}
}
See the API and examples of TextField here: http://www.material-ui.com/#/components/text-field
You need function that you will throw in your TextField component and with onChange you can get value of input.
handleChange(e){
Console.log(e.target.value)
}
And in TextField
<TextField onChange={this.handleCahnge}/}
Or use refs
<TextField ref="textfield" />
And get value with this.refs.textfield.getValue()

Resources