Sync validation on a radiogroup (v6) - reactjs

How can I display sync-validation errors for my radiogroup when using the v6 version of redux-form? One option would be to create multiple renderField functions, in which only one (the last one) would display the errors. I currently have it setup like this:
const renderField = ({ input, meta: { touched, error } }) => (
<span>
<input
{...input}
/>
{
touched &&
error &&
<div>
{error}
</div>
}
</span>
);
// Form-component
// I loop trough multiple values
<Field
type="radio"
component={renderField}
id={`${field.name}-${value}`}
value={value}
name={field.name}
/>
<Field
type="radio"
id={`${field.name}-${value}`}
value={value}
name={field.name}
/>
In this way, the errors get presented multiple times (for each value). I could pass an extra prop when it is the last value, to enable the errors for just that field. Although that would work, it feels kinda nasty.

This is an interesting question. Another option would be to write a component that was just in charge of rendering errors.
const renderError = ({ meta: { touched, error } }) =>
touched && error && <div>{error}</div>
Then, after you had rendered your radio buttons, you could do a:
<Field name={field.name} component={renderError}/>

Related

React-final-form - input losing focus after every keystroke

import React from "react";
import { Field, Form } from "react-final-form";
export function LogInDialog(props: { open: boolean; onClose: () => void }) {
const onSubmit = vals => {
alert(JSON.stringify(vals));
};
console.log("logindialog");
return (
<Form
key="unique_key_0"
onSubmit={onSubmit}
render={({ handleSubmit, form, submitting, pristine, values }) => (
<form onSubmit={handleSubmit} key="unique_key_1" id="unique_id_1">
<Field
key="unique_key_2"
id="unique_id_2"
name="email"
component={({ input: { onChange, value }, label }) => (
<input
key="unique_key_3"
id="unique_id_3"
type="text"
value={value}
onChange={onChange}
/>
)}
></Field>
</form>
)}
/>
);
}
The input is losing its focus after every keystroke. In devtools, I can see the HTML form is created anew every time (it flashes pink). The React component itself however goes through rendering only once.
There are similar questions, however all of them suggest using unique keys. Such a solution doesn't seem to be working here.
Why is the input losing its focus over and over again? How do I fix it?
https://codesandbox.io/s/busy-torvalds-91zln
Since an inline lambda is used for the component, its identity changes every render.
While according to many other questions an unique key should be enough, moving the component function outside the master component fixes it altogether.

Mutator to covert text to uppercase

I tried different ways to implement mutator to convert text to uppercase as soon as user input text in the text field. But was not yet successful. The example provided by Erick seems correct, but maybe I am missing something.
/** Converts a form value to uppercase **/
const upper = ([name], state, { changeValue }) => {
changeValue(state, name, (value) => value.toUpperCase())
}
<Form
onSubmit={onSubmit}
mutators={{
...arrayMutators,
upper
}}
render={({
handleSubmit,
mutators: { push, pop, upper }, // injected from final-form-arrays above
pristine,
reset,
submitting,
values
}) => {
return (
<form onSubmit={handleSubmit}>
<div>
<label>Company</label>
<Field name="company" component="input" onChange={(e) => upper('company')} />
</div>
</form>
)}
}
/>
It's throwing an error when calling toUpperCase on value as value is coming undefined there. Really appreciate any help!
Update: 27-Oct-2018
I have realized we can use parser too, to solve this problem:
upper = value => {
return value ? value.toUpperCase() : ''
}
<Field name="company" component="input" parse={this.upper} />
Still looking for how mutator works and what's the error in my code.
Already Tried:
Mutate state based on existing fields
How to set/change Field value from external user action 🏁 React Final Form
As I know about react-final-form you can get this data directly
I will suggest, you can use this code
onChange={(event, value) => input.onChange(value.toUpperCase())}
https://codesandbox.io/s/0x9y71nwyp

Is there a way to get access to redux-form errors from inside the Container with reduxForm V7?

Previously, in Redux-Form V5, I was accessing errors as email.error and password.error from inside the render function.
In V7, my CSS is giving me grief to do it this way:
const renderInput = (field) => {
const { meta: { touched, error } } = field
return (
<div>
<input type={field.type} placeholder={field.placeholder} {...field.input} />
<div className="inputErrorText">
{touched ? error : ''} // this doesnt work due to my CSS
</div>
</div>
)
}
// ...inside the Container:
<div className="ui left icon input">
<i className="user icon"></i>
<Field
name="email"
component={renderInput}
type="text"
placeholder="Enter your Email"
/>
</div>
// Below is the old way I was doing it
{/*email.touched && email.error && <div className="inputErrorText">{email.error}</div>*/}
If I render the errors via renderInput(), the CSS gets mangled due to what looks like some position relative+absolute reasons, so I need the errors to render below that last div at the bottom of my code above.
How can I deal with rendering the field errors outside renderInput() and/or elsewhere in the <form>. I think my question centers around the field input parameter of renderInput(). How to access it inside the Container? Is it available on this.props anywhere?
I just got it working. I found this source: Redux-form 6.0.0 access error outside Field component which illustrates a way to use the Fields component of redux-form V6 & 7.
I wasn't able to get it working as shown there. I'm not entirely sure at this point, but it was throwing all kinds of "cannot read property touched of undefined". I tried many combinations of if (!fields) return else destructure, and about 20 different combinations and I just couldn't get it to iterate through using Object.keys(). I was able to console log easily fields.email.input and see everything, but as soon as I started digging into meta, it started throwing undefined even while it was logging the values sometimes. The weird thing is untouched was always false not undefined, so it was fairly infuriating, but I digress.
Another person may have more luck with that above solution. Fields is definitely what a person wants to use to gain control over errors in Redux-form V6-7.
I did however, get it to work like this:
import { reduxForm, Field, Fields } from 'redux-form'
const fieldNames = [
'email',
'password'
]
const renderInput = (field) => {
return (
<input type={field.type} placeholder={field.placeholder} {...field.input} />
)
}
// inside the Container (class methods)
renderEmailError({ email }) {
const { touched, error } = email.meta
if (touched && error) return <div className="inputErrorText">{error}</div>
return null
}
renderPasswordError({ password }) {
const { touched, error } = password.meta
if (touched && error) return <div className="inputErrorText">{error}</div>
return null
}
// Inside render function
<div className="field">
<div className="ui left icon input">
<i className="user icon"></i>
<Field
name="email"
component={renderInput}
type="text"
placeholder="Enter your Email"
/>
</div>
<Fields names={fieldNames} component={this.renderEmailError} />
</div>
x
I was not able to get it working with the "standard" implementation using Field because my CSS simply does not allow for a div to be placed along with the input. I could not alter the CSS because of the way it places the icons on top of the input fields.
I experimented with moving the entire 'fieldset' into the renderInput() function, but I became equally stuck because of the onClick handler when you click the eyeball to expose the password (UX substitute for passwordConfirm field). I was not able to update the component state from outside the class, nor was I able to call the function properly from outside the class.
Additionally, I also learned that you cannot manipulate an input's type if it is password using document.querySelector('input').type because it is a security risk.

Displaying error messages onChange in redux-form

I'm trying to use redux-form Field (together with Material-ui) and validation. It appears that the error messages are shown when I navigate away from the field (i.e. onBlur). What I would like to achieve is to do validation on the fly as the user types, and display error messages onChange event. How would I go about achieving this behavior?
import { TextField } from 'redux-form-material-ui';
import { Field, reduxForm } from 'redux-form';
const MyForm = (props) => (
<form>
<div className="form-group">
<Field
name="foo"
type="text"
hintText="Foo"
component={TextField}
/>
</form>
);
export default reduxForm({
form: 'MyForm',
validate
})(MyForm);
The default behaviour of validation is that messages are only displayed when fields are touched (i.e. onBlur).
I suppose you could work around that by using the touch method in componentWillMount, so that it becomes touched upon mount:
componentWillMount() {
const { touch } = this.props;
touch('foo');
}
That does however have the drawback of possibly showing any errors directly when the form is loaded, but in this case validation is triggered in onChange right away.
Have you played with the example in CodeSandbox? Like Dennis suggested, you could call "touch", though depending on your need you may choose to do this onChange:
<Field
name="username"
type="text"
component={renderField}
label="Username"
onChange={() => touch('username')}
/>

Why does redux form return string instead of the object?

I am trying to access the touched property on my redux form, but for some reason when I print the field props I only the value instead of the object. What am I missing?
import { reduxForm, Field } from 'redux-form';
render() {
const { fields: { email, phone }, handleSubmit } = this.props;
console.log(email) //prints just the value "email" instead of the field object with the touched method, etc. When I do console.log(email.touched) I get undefined error.
return (
<form onSubmit={handleSubmit(this.onSubmit)}>
<Field name="email" component="input" type="email" { ...email } />
<Field name="phone" component="input" type="number" { ...phone } />
</form>
);
}
export default ReduxFormTest = reduxForm({
form: 'uniqueForm',
fields: ['email', 'phone']
})(TestClass);
There were breaking changes in redux-forms from v5 to v6. Previously you could do something similar to what you have to access the touched field. If you want to do something similar to see if there are errors on a field, you need to create your own component to pass to redux-form's Field component.
Your custom component
const CustomComponent = function(field) {
return (
<div>
<input
type={field.type}
{...field.input}
/>
{field.meta.touched && field.meta.error && <div className='error'>{field.meta.error}</div>}
</div>
)
}
Then using it with the Field component
<Field name="my-prop" component={CustomComponent} />
Also take a look at the migration guide, hope this helps!
You are confusing v5 syntax with v6 syntax. In v6, your decorated form component is no longer passed this.props.fields. Re-read the migration guide, like #tyler-iguchi said.

Resources