How to clear the text field in formsy material ui React - reactjs

Hi I am using React 14 and writing it in ES6. I am using formsy-material-ui for form validations. There is a scenario where I want to clear the value of text field on click of a button.
I tried the following code
<FormsyText
name="email"
ref="email"
validations="isEmail"
validationError="Invalid Email"
hintText="Email"
value={this.state.emailValue}
/>
And on click of the button, I am executing the following line of code
this.setState({emailValue : ''});
But the text field is not getting cleared.
How to clear it.
Pls help.

So, if you were using a controlled input (maybe using directly the TextField from Material-ui) - your code would be right, however the FormsyText component handle it's value internally.
If you pass a value or defaultValue it'll just be used when it's rendered, you can check it here.
I only see one way to clear the value now, in an imperative style.
this.refs.email.setState({ value: "" })
Note: I suggest you to change the way you're using the ref. Using refs with a string is deprecated and probably will be removed in the future. Instead you should pass a function that's gonna receive that component. https://facebook.github.io/react/docs/more-about-refs.html
Example:
<FormsyText
name="email"
ref={(node) => this._emailText = node}
validations="isEmail"
validationError="Invalid Email"
hintText="Email"
value={this.state.emailValue}
/>
//And to clear it
this._emailText.setState({ value: "" })

Try reset field after setState:
this.setState({emailValue : ''});
this.refs.email.reset()
Also you can reset all form.
this.refs.form.reset()

const formRefdeposit = useRef(null);
<Formsy
onValidSubmit={handleSubmit}
onValid={enableButton}
onInvalid={disableButton}
ref={formRef}
>
....Form Fields
</Formsy>
if you have class in your js file then use
this.formRef.current.reset();
if without class then use
formRef.current.reset();

Related

Conditionally enabling a form button with react-hook-form and material ui

I'm creating a React form with Material UI. My goal is to force the user to answer all the questions before they can click the download button. In other words I'm trying to leave the download button in the disabled state until I can determine that values are set on each field. I've tried to get this working with and without react-hook-form.
What I've tried
Without react-hook-form...
I have my example in coding sandbox here:
https://codesandbox.io/s/enable-download-button-xwois4?file=/src/App.js
In this attempt I abandoned react-hook-form and added some logic that executes onChange. It looks through each of the formValues and ensures none of them are empty or set to "no answer". Like this:
const handleInputChange = (e) => {
// do setFormValues stuff first
// check that every question has been answered and enable / disable the download button
let disableDownload = false;
Object.values(formValues).forEach((val) => {
if (
typeof val === "undefined" ||
val === null ||
val === "no answer" ||
val === ""
) {
disableDownload = true;
}
});
setBtnDisabled(disableDownload);
The problem with this approach, as you'll see from playing with the UI in codesandbox, is that it requires an extra toggle of the form field value in order to detect that every field has been set. After the extra "toggle" the button does indeed re-enable. Maybe I could change this to onBlur but overall I feel like this approach isn't the right way to do it.
Using react-hook-form
With this approach...the approach I prefer to get working but really struggled with, I ran into several problems.
First the setup:
I removed the logic for setBtnDisabled() in the handleInputChange function.
I tried following the example on the react-hook-form website for material ui but in that example they're explicitly defining the defaultValues in useForm where-as mine come from useEffect. I want my initial values to come from my questionsObject so I don't think I want to get rid of useEffect.
I couldn't figure out what to do with {...field} as in the linked material ui example. I tried dropping it on RadioGroup
<Controller
name="RadioGroup"
control={control}
rules={{ required: true }}
render={({ field }) => (
<RadioGroup
questiontype={question.type}
name={questionId}
value={formValues[questionId]}
onChange={handleInputChange}
row
{...field}
>
but I get an MUI error of : MUI: A component is changing the uncontrolled value state of RadioGroup to be controlled.
Also, I don't see that useForm's state is changing at all. For example, I was hoping the list of touchedfields would increase as I clicked radio buttons but it isn't. I read that I should pass formState into useEffect() like this:
useEffect(() => {
const outputObj = {};
Object.keys(questionsObject).map(
(question) => (outputObj[question] = questionsObject[question].value)
);
setFormValues(outputObj);
}, [formState]);
but that makes me question what I need to do with formValues. Wondering if formState is supposed to replace useState for this.

REACT ADMIN | TEXTINPUT CHANGE VALUE

how can I change the value of an TextInput in react-admin.
My idea was
<TextInput label="..." source="..." value="MY VALUE" />
But that doesn't work.
pls help.
You can't do this with the react-admin's TextInput as it is a connected field to the backing react-final-form form and hence you don't control the input.
You should state what is your final aim. I can think of two options:
If you want to have a controlled input you can simply use material-ui's TextField and pass to it your custom value as well as handle the onChange event.
If you don't want to control the value by yourself but alter it in the form state under some condition, you can then use the hook provided by react-final-form:
const form = useForm();
form.change("myValue", newValue);
...
<TextInput label="My Value" source="myValue" />
Since react-adminv4.0.0 library no longer uses react-final-form instead it uses react-hook-form. So you would need to change your relevant code to use it as well.
import {useFormContext} from "react-hook-form";
...
const {setValue} = useFormContext();
setValue("myValue", newValue);
If the value of your input is null or undefined you can use the initialValue prop to set the value when the page loads.
<TextInput source="mySource" initialValue="MY VALUE" />
See React-Admin Input Docs: https://marmelab.com/react-admin/Inputs.html#common-input-props
If you are looking to dynamically change the value after the page has loaded, I would recommend following Kia's answer to leverage the useForm hook.

Simulate click event in React with TypeScript material-ui

I'm rendering some material-ui TextFields. By manually typing the value inside it, it'll work properly. It is using handleChange() (change) and handleBlur() (autosave) to handle those events. but the scenario is I have to update the value not by manually typing but from the store.
So, if I pass the value from the store, it is not actually updating the value unless I click inside the field and click away or tab out. the value is showing inside the field but not invoking handleChange() and handleBlur() which are the only way to update the value inside. Also I have to type at least a value.
Approach:
I set an onFocus to the field and on it's handleFocus, I'm trying to either simulating click() and blur() or calling handleClick() and handleBlur(). If I simulate a click event,
Uncaught TypeError: element.click is not a function
If I try to call handleChange() and handleBlur()
readonly refO: React.RefObject<HTMLInputElement>;
constructor(props: InputProps) {
super(props);
this.refO = React.createRef<HTMLInputElement>();
}
...
<TextField
autoFocus
inputRef={this.refO}
id={this.labelId}
required={required}
label={label}
error={error}
value={this.setValue()}
onBlur={handleBlur}
onChange={handleChange}
disabled={disabled}
fullWidth
type={type}
InputLabelProps={InputLabelProps}
InputProps={{ className: cx({ [classes.modified]: isModified }) }}
onFocus={this.handleFocus}
/>
What can I do inside handleFocus() in order to achieve this. or the proper approach to achieve this. I'm very new to TypeScript. is my approach wrong or any other way to overcome this.
handleFocus = (element: HTMLInputElement) => {
element.click();
this.props.handleChange();
this.props.handleBlur();
}
PS: cannot add more code due to some sensitivity issues.
solved the issue.
i knew it has to be done from inside the handleFocus. but what i was doing call other event handlers from it. then i thought why should i. the function has been invoked so just update the values from it.
handleFocus = (value) => {
// update my value
}
it's unconventional but all we require is the result.
ps: i even pinged few people on twitter(this has put our reputation on the stake. it was a race against time). i was that desperate. i apolagize to them.

Dynamically set a property value for an Input in Semantic UI React

I have an Input element that I want to display an error on when the form validation fails.
<Input ref="amount" error={false} />
When the user enters an incorrect amount, I want to change "error" to "true". How can this be done?
I have tried:
this.refs.amount.props.error = true;
Which seems bad but I'm not sure how else. If I add a conditional statement in the definition of the Input element, that seems to only evaluate once and then remain the same. Do I need to force an update on the element? If so, how?
Yes it's possible to validate the input when the form is submitted.
All you need is to keep track on input value and use same approach as #SajithDilshan for the input error.
this.state = {
error: false,
value: ''
}
...
render(){
return
...
<Input
ref="amount"
value={this.state.value}
error={this.state.error}
/>
...
}
Then onSubmit should looks like:
onSubmit(e){
const isError = this.state.value === '';
this.setState({error: isError});
// rest of your logic
}
Hope it will help!
Use the onChange() method on the input as below.
<Input ref="amount" onChange={this.onInputChange} error={this.state.error} />
After that implement the onInputChange() method as below in your component.
onInputChange = (e) => {
if (e.target.value === "") { // logic to validate the input
this.setState({error: true});
} else {
this.setState({error: false});
}
}
Note that this will add error property to the state.
Further, you should not modify the props within a component. Props are passes from parent component to the child component as immutable inputs.
This is not exactly the answer, but still:
This type of fiddling with each possible state of form element (valid, invalid, warning, show tooltip, was edited, in focus, left focus, was submitted, submit failed or not, etc) becomes to much trouble when the form grows beyond 1 input field.
I would suggest to use redux-form package that integrates with semantic-ui-react` almost perfectly and provided you have provided it with the validate function does everything else for you. It takes some time to understand the basics of it, but it really pays.

React Redux way of handling enable-disable of DOM elements

I have a form where i have to enable/disable certain DOM elements based on the state of other DOM elements. For e.g. I have a radio button, on the click of which a drop down should be enabled.
Now for implementing this, should I again follow the redux way of disposing an action when the radio is clicked and then within the reducer change the state and then enable/disable the dropdown?
Does redux-form in any way simplify this process? What is the best practice to implement this in a react-redux setup?
I use redux-form for conditional inputs. For example, I have a checkbox that when checked, should display a text area to explain the true input. That looks like this:
<div className="checkbox">
<label for="trueInput">
<input type="checkbox" {...trueInput} />
Is this input true?</label>
</div>
<div className={!trueInput.value ? 'conditional-input' : ''}>
<label for="trueInputExplanation">Why is this input true?</label>
<input className="form-control" {...trueInputExplanation} />
</div>
The class .conditional-input has styling to hide the element. I'd imagine you could do this the same way for disabled, by way of using a ternary function that returns true or false, depending on the conditions you need.
Redux Form keeps track of everything in the store. (It's easy to see what's going on with the Redux Chrome dev tool.) Say I have a master checkbox whose enablement allows me to toggle a slave checkbox. So I want to put the master state read from the form into props:
const mapStateToProps = (state) => {
const isMasterChecked = state.mySetting.isMasterChecked;
const form_mySetting = state.form.mySetting;
const form_isMasterChecked = form_mySetting ? form_mySetting.values.isMasterChecked : null;
return {
isMasterChecked,
form_isMasterChecked
}
};
and then for the form you have
const {isMasterChecked, form_isMasterChecked} = props;
const shouldDisable_slaveCheckbox= () => {
if (form_isMasterChecked == null) return isMasterChecked; // the form is not fully built yet, so use "real" store value instead of reading the form via store
return form_isMasterChecked;
};
<Field name="isSlaveChecked" component="input" type="checkbox" disabled={shouldDisable_slaveCheckbox() ? "" : "disabled"}/>
Use sparingly, as this approach may cause entire form redraw.

Resources