Empty Material-UI textfield after submitting the form - javascript

How can I clear value from the TextField after submitting the form? All of the components in the code are functional components, not the class ones. Here is one of the TextFields, the others are similar to this one. I can make the type='search' as in the code bellow but then a user needs to press a button to clear the value and even then the error check is complaining about the field being empty.
Would it be better to try and refresh the component? This form is in a sidebar in my app.
<form onSubmit={onSubmitHandler} className={classes.root}>
<TextField
name='firstName'
inputRef={register({
required: "Please enter first name",
validate: value => isEmpty(value)
})}
label={translate('invitation.first_name')}
error={!!errors.firstName}
type='search'
autoFocus
fullWidth
/>

There is a value property that you have to pass to the TextField component. check example below:
class SomeComponent extends Component {
state = {value: ''}
resetValue = () => {
this.setState({value: ''});
}
render() {
return (
<div>
<TextField
...
value={this.state.value}
/>
<button onClick={this.resetValue}>Reset</button>
</div>
)
}
}

Related

How to auto tab between Formik Field?

I have a component for 4 digit code of phone validation. By itself it works fine and looks good as well. The only issue I am facing - I can't autotab between numbers. I have to go to each input manually and write the number. Is it possible to do with Formik Field?
This is my piece of code:
<Formik
onSubmit={values =>
VerifyGarageFunc({ code: values.code.join(''), requestId: PhoneCodeData.data }, data.showModal)
}>
{({ values, handleChange, handleSubmit }) => (
<form onSubmit={handleSubmit}>
<FieldArray
name="code"
render={arrayHelpers => (
<div className={styles.inputWrapper}>
{values.code.map((item, index) => (
<div key={index}>
<Field
name={`code.${index}`}
type="text"
component={CustomInput}
onChange={handleChange}
value={values.code[index]}
/>
</div>
))}
</div>
)}
/>
<LoginActionButton onSubmit={handleSubmit} text={'Send'} />
<FieldArray />
</form>
)}
</Formik>
I tried https://www.npmjs.com/package/react-auto-tab but it works only with <input/>, for some reason it doesn't work at all with Formik Field.
P.S. I am using Next.js with React.js
You'll likely have more luck with a hook based solution. Install https://github.com/Romr1ch/react-pin-input-hook, which just does the logic without being opinionated about display.
Create a new component called PinInput and create a new field using the formik hook primitives.
Ive setup an example codesandbox: https://codesandbox.io/s/react-pin-input-hook-custom-input-1ze5dv?file=/src/App.js, but note this doesn't use your exact components as I don't have them. The below code should match closer your exact case.
import React from 'react'
import { useField } from 'formik'
import { usePinInput } from 'react-pin-input-hook'
export const PinInput = (props) => {
const [field, meta, helpers] = useField(props)
const { fields } = usePinInput({
values: field.value,
onChange: (values) => {
helpers.setValue(values)
},
})
return fields.map((fieldProps, index) =>
<CustomInput key={index} type="text" {...fieldProps} />
)
}
Then in your main file do this (by the way if you use Form component from Formik you dont need to do any of the onSubmit binding yourself, so I changed that along the way -- the button can just be "submit" type):
<Formik
onSubmit={values =>
VerifyGarageFunc({ code: values.code.join(''), requestId: PhoneCodeData.data }, data.showModal)
}>
<Form>
<PinInput name="code" />
<LoginActionButton type="submit" text={'Send'} />
</Form>
</Formik>
Note that this lib requires your CustomComponent to attach a ref to the underlying thing that needs focusing so you'll need to use forwardRef on that component and attach it to the underlying input. It also needs to support onBlur, onFocus, onChange and onKeyDown.

Set the value of a form based on state in React

Using Formik for validating some fields, if a state value is true I want that the value of a fields to be copied to the value of another one.
For example, value of mainAddress to be copied to address.
There is a state variable, setAddress which is set on false but it can be changed to true when a checkbox is clicked.
When this variable is set on true I want that the value of mainAddress to be copied to address
This is the code that works fine without copying that value:
import React from 'react';
import { Formik, Form, Field } from 'formik';
import { Input, Button, Label, Grid } from 'semantic-ui-react';
import * as Yup from 'yup';
import { Creators } from '../../../actions';
import './CreateCompanyForm.scss';
class CreateCompanyForm extends React.PureComponent {
constructor(props) {
super(props);
this.state = { // state variables
address: '',
mainAddress: '',
setAddress: false,
};
}
handleSubmit = values => {
// create company
};
toggleAddress = () => { // it toggles the value of setAddress
this.setState(prevState => ({
setAddress: !prevState.setAddress,
}));
};
render() {
const initialValues = { // the address and mainAddress are set to '' at the start
address: '',
mainAddress: '',
};
const validationSchema = Yup.object({
address: Yup.string().required('error'),
mainAddress: Yup.string().required('error'),
});
return (
<>
<Button type="submit" form="amazing"> // button for submit
Create company
</Button>
<Formik
htmlFor="amazing"
initialValues={initialValues}
validationSchema={validationSchema}
onSubmit={values => this.handleSubmit(values)}>
{({ values, errors, touched, setValues, setFieldValue }) => (
<Form id="amazing">
<Grid>
<Grid.Column> // mainAddress value
<Label>Main Address</Label>
<Field name="mainAddress" as={Input} />
</Grid.Column>
<Grid.Column> // address value
<Label>Address</Label>
<Field name="address" as={Input} />
<div>
{this.state.setAddress // here is how I've tried to set that value
? values.address.setFieldValue(values.mainAddress)
: console.log('nope')}
{touched.address && errors.address ? errors.address : null}
</div>
</Grid.Column>
</Grid>
<Checkbox
label="Use same address"
onClick={() => this.toggleAddress()}
/>
</Form>
)}
</Formik>
</>
);
}
}
So I've tried more ways to solve it but without success. Now in the code it is:
{this.state.setAddress
? values.address.setFieldValue(values.mainAddress)
: console.log('nope')}
Other one was: (this.state.setAddress ? values.address = values.mainAddress)
None of them work. Is it possible to get the value from values.mainAddress and copy it to values.address? Or to its input?
You can rewrite the Field component for address accordingly.
<Field name="address">
{({
field, // { name, value, onChange, onBlur }
}) => {
values.address = values.mainAddress;
return (
<div>
<input
{...field}
type="text"
placeholder="Address"
/>
</div>
);
}}
</Field>
Here we are setting the value of address field to values.mainAddress if setAdress checkbox is checked else we let formik value to fill it.
Here is the working codesandbox code - https://codesandbox.io/s/fervent-tereshkova-sro93?file=/index.js
Formik also provides values object you could use that for updating address value same as mainAddress. Just provide name attribute to both input fields then assign like this - props.values.address = {...props.values.mainAddress}

Formik field from nested component not updating

I have the following scenario:
main component with a few fields that Formik handles. Everything fine here.
sub component that renders inside the main form and uses Formik's Field component, same as the fields in the main component do. These fields are not getting updated.
Main component:
...
return (
<Formik
enableReinitialize
initialValues={{
name: this.state.name,
newName: this.state.newName, // this field is inside the nested component
}}
validationSchema={mySchema}
onSubmit={...}
>
{
({ errors, values, ... }) => (
<Form ref={this.formRef}>
...
<Field name="name" type="text" />
...
<NewNameForm />
</Form>
)
}
</Formik>
);
NewNameForm component:
...
return (
<div>
<Field name="newName" type="text" />
</div>
);
Is my approach wrong, can I just nest components with extra fields like this? newName isnt' getting updated so I'm obviously doing something wrong.
I've solved this by passing Formik's setFieldValue method to subcomponent's props like this:
onNameChange={(name) => {
setFieldValue('newName', name);
}}

Reusable form fields in React

If i have the following dialog/modal:
<Modal
open={this.state.createAccountModalOpen}
trigger={<Link size="m" theme="bare" href="#" className="main-menu-item" onClick={this.handleOpenModalCreateAccount}>Create account</Link>}
closeIcon
onClose={() => { this.setState({
createAccountModalOpen: false,
}); }}
>
<Header icon='add user' content='Create account' />
<Modal.Content>
<Form />
</Modal.Content>
<Modal.Actions>
<Button color='green' onClick={this.handleSubmit}>
<Icon name='add user' /> Create account
</Button>
</Modal.Actions>
</Modal>
Basically this is a React Semantic-ui Modal/Dialog. Now What i want to do is make Form reusable (the Form component contains 4 input fields), so i can use it in other modals or components. What would be the best way so that when I click on Create account, it gathers the data from the form and then submits it?
Do I have to pass functions to the Form to try store the data in the main Modal component? or is there a better way to get the validated data from the form?
I’m on my phone so I’m limited.
You want to define your custom function in the parent component where you call your Modal. Then pass that function to it as a prop modal onComplete={this.submitEmail}
Then in your modal component call this.props.onComplete in your handleSubmit.
Then from here out you can define the custom function you want to use wiTh the model and pass it through with onComplete={whateverFunction}
In order to only show the inputs that you want you could set up a series of render if statements. Then when you call your Modal you can pass through renderIfText={“email”} and in your model if this.props.renderIfText=email render email input.
import React from 'react';
class ReusableModalForm extends React.Component {
constructor(props){
super(props);
this.state ={
};
}
handleChange(e) {
let {name, value} = e.target;
this.setState({
[name]: value,
usernameError: name === 'username' && !value ? 'username must have a value' : null,
emailError: name === 'email' && !value ? 'email must have a value' : null,
passwordError: name === 'password' && !value ? 'password must have a value' : null,
});
}
handleSubmit(e) {
e.preventDefault();
this.props.onComplete(this.state)
}
render() {
return (
<Modal
open={this.state.createAccountModalOpen}
trigger={<Link size="m" theme="bare" href="#" className="main-menu-item" onClick={this.handleSubmit}>{this.props.buttonText}</Link>}
closeIcon
onClose={() => { this.setState({
createAccountModalOpen: false,
}); }}
>
<Header icon='add user' content='Create account' />
<Modal.Content>
<Form />
</Modal.Content>
<Modal.Actions>
<Button color='green' onClick={this.handleSubmit}>
<Icon name='add user' /> {this.props.buttonText}
</Button>
</Modal.Actions>
</Modal>
);
}
}
export default ReusableModalForm;
In order to make your <Form /> reusable you need to determine what are the inputs/outputs to your Form and allow any potential parent component to access/manipulate it via props.
Perhaps something like:
<CreateAccountForm
input1DefaultValue={...}
input2DefaultValue={...}
onSubmit={yourCreateAccountFormHandler}
/>
Do I have to pass functions to the Form to try store the data in the main Modal component? or is there a better way to get the validated data from the form?
It depends on how you implement Form and your input fields.
I would recommend react-form library or, if you want to have your own implementation - using redux state and wire your inputs/form to redux.
If no redux then you will need to store the state of inputs in the modal.
Whenever you compose components, you share data between them using props. I will be passing "name and label" props to stateless functional component named;
input.js
import React from "react";
const Input = ({name,label}) => {
return (
<div className="form-group">
<label htmlFor={name}>{label}</label>
<input
autoFocus
name={name}
id={name}
className="form-control"
aria-describedby="emailHelp"
/>
);
};
export default Input;
form.js
import React, { Component } from "react";
import Input from "./common/input";
class RegisterForm extends Form {
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input name="username" label="username" />
<input name="email" label="email" />
<input name="password" label="password" />
</form>
</div> ); } }

React focus on child component input

I currently implement Redux-Form in order to add InputFields to my application. Is there are way to manually focus on an input of a child component?
Code for adding child component:
<Field name="Quantity" ref="quantity" onKeyPress={(event) => this.handleKeyPress('inventory', event)} component={ InputField }/>
Code for child component:
render() {
const { input } = this.props;
const inputClass = classNames({ 'parsley-error': this.props.meta.touched && this.props.meta.error }, 'form-control')
return (
<div>
{this.props.meta.touched && this.props.meta.error && <span className="parsley-error-message">{this.props.meta.error}</span>}
<Input {...input} className={inputClass} onKeyPress={this.props.onKeyPress} standalone type="text" placeholder={this.props.placeholder}/>
</div>
)
}
Current implementation attempt at focus:
handleKeyPress(value, event){
if(event.charCode == 13){
this.refs["inventory"].getDOMNode().focus();
}
}
I hard coded to focus inventory just for test purposes
Inside your Input component you should be able to do:
`<input type="text" autoFocus />`
Note the F has to be capitalized. I haven't test this on newly generated components but in theory it should work.

Categories

Resources