Admin-on-rest: Input validation based on field value - admin-on-rest

In a SimpleForm of an Edit view I would like to set the minimum value of the group size based on the current number of members inside.
The entity is:
group = {members: 3, size: 10}
What I'm trying to achieve looks like:
export const UserCreate = (props) => (
<Edit {...props}>
<SimpleForm>
<DisabledInput label="Members number"
source="members" />
<NumberInput label="Group size"
source="size"
validation={{min: members, required: true}} />
</SimpleForm>
</Edit>
);

This is explained in the documentation, in the Per Field Validation: Function Validator part.
In a nutshell, you define a function which will take 2 parameters: the value to validate and values which contains all the form values

Related

How do I validate a radio input in Yup/Formik?

I'm using Yup to validate my Formik form, but I have no idea how to validate a radio input in Yup/Formik.
You validate the radio group. The only validation failure that is possible, is if you don't have a default button selected, and the user doesn't select any of the radio buttons.
Given:
<RadioButtonGroup
id="radioGroup"
label="One of these please"
value={values.radioGroup}
error={errors.radioGroup}
touched={touched.radioGroup}
>
<Field
component={RadioButton}
name="radioGroup"
id="radioOption1"
label="Choose this option"
/>
<Field
component={RadioButton}
name="radioGroup"
id="radioOption2"
label="Or choose this one"
/>
</RadioButtonGroup>
Validation code:
radioGroup: Yup.string().required("A radio option is required")
As used in context:
<Formik
...
validationSchema={Yup.object().shape({
radioGroup: Yup.string().required("A radio option is required"),
...
})}
Copied from this larger validation example:
https://gist.github.com/mrtony/c1ba5f8ec4122d2866b292fc36152d34
your radioInputGroup values:
state = {
gender: [
{
id: 0,
type: "woman",
text: interpreter("ImFemale")
}, {
id: 1,
type: "man",
text: interpreter("ImMale")
}
]
}
and your yup validationSchema:
ValidationSchema = Yup.object().shape({
gender: Yup.boolean().required().oneOf([0 , 1]),
});
note: you should to use gender values in .onOf() function.
if you want to show some msg for error message, use this code for yup validationSchema:
ValidationSchema = Yup.object().shape({
gender: Yup.boolean().required().oneOf([0 , 1], 'Selecting the gender field is required'),
});
Theoretically it shouldn't be different from any other value. You're tracking the radio value (or Formik's tracking it for you) somewhere in your state as a string most likely, and you simply need to apply the rules to the value that you're storing.
If you want to make sure the value matches only the presented radio options, you can use oneOf to accomplish that, but otherwise it's no different than any other scalar value.

Redux Form : setting value of hidden input in a loop

I am working with Redux Form and in that I am trying to set the value of Hidden Input field in a loop. But the value doesn't get submitted as the field was never touched. Is there a way to solve this or am I missing something?
const renderEmployeeFields = (fields) => {
return fields.map((e, i) => {
return (
<Field
key={e._id}
name={`employeeSchedule[${i}].employee`}
component={renderTextField}
employeeId={e._id}
label={e._id}
/>
)
})
}
const renderTextField = ({ input, label, employeeId}, autocompleteKey) =>
<Input key={`${label}-input`} autoComplete={`${autocompleteKey}-${label}`} autoFocus {...input} value={employeeId} type='hidden'/>
You have to set the value using the initialValues property (https://redux-form.com/7.4.2/docs/api/reduxform.md/#-code-initialvalues-object-lt-string-string-gt-code-optional-) so that they will be available on submit.
You don't need then the hidden input.

Redux Form - How to validate async blur field arrays?

I have a FieldArray like this:
renderLanguages = fields => (
<div>
{fields.map(fieldName => <Field name={fieldName + '.iso'} component="input" type="text" />
</div>
)
<FieldArray name="languages" component={renderLanguages} />
And i like to validate it in a async way:
const asyncValidate = values => {
console.log(values);
}
export default reduxForm({
form: 'languagesForm',
asyncValidate,
asyncBlurFields: ['languages']
})(LanguagesForm)
My asyncValidate never gets called. I wonder if i have to specify the asyncBlur fields in an other way. Or if redux-form does not provide the async validation of field arrays.
To get Redux-form FormArray working with the asyncValidate, it requires to pass the field as languages[].<nameOfTheFieldOfChildComponet> but not languages only.
I think its good design too as generally, we don't validate asynchronously on change of any parameter but a specific parameter.
Here is the working example:- https://codesandbox.io/s/mq8zz58mrj
const asyncValidate = values => {
console.log(values);
}
export default reduxForm({
form: 'languagesForm',
asyncValidate,
asyncBlurFields: ['languages[].name']
})(LanguagesForm)

FieldLevelValidationForm - How to make it configurable

I am running into this situation:
I want to apply multiple validations on a field which like example below:
<Field name="username" type="text"
component={renderField} label="Username"
validate={[ required, maxLength15 ]}
/>
But I want to make the 15 as a configure number instead.
For example, userNameValidatiorConfig = [required, {maxLength: 15}]
Any ideas on this?
The validate prop of Field contains usual javascript functions. Thus you could do something like
validate={(value) => maxLength(15)(value)}
That is if your validation functions look like
const maxLength = (max) => (value) => value && value.length > max ? "Bad input!" : undefined;

In Redux Forms, how do I validate one field based on the value of another?

I am using Redux Form version 6.4.3 and I'm trying to validate two date fields such that the 'to' date must always be before the 'from' date.
Other examples say I ought to be able to refer to the fields array in props but there is no such array. The form state has an array called registeredFields however but those just seem to be of the form {name: 'dob', type: 'Field'}
Here is my form code
import React from 'react'
import DatePicker from 'react-bootstrap-date-picker'
import moment from 'moment'
import {Field, reduxForm} from 'redux-form'
import {Form, Row, Col, Button, FormGroup, ControlLabel, FormControl, HelpBlock} from 'react-bootstrap'
// validations
const required = value => !value ? 'This field is required' : undefined
const maxDate = max => value =>
value && moment(value).isAfter(max) ? `Must be before ${max}` : undefined
const minDate = min => value =>
value && moment(value).isBefore(min) ? `Must be after ${min}` : undefined
const renderDatepicker = ({ input, label, hint, showTodayButton, meta: { pristine, touched, warning, error } }) => {
const validationState = pristine ? null : error ? 'error' : warning ? 'warning' : null
return (
<FormGroup validationState={validationState}>
<Col componentClass={ControlLabel} sm={3}>{label}</Col>
<Col sm={3}>
<FormControl
{...input}
componentClass={DatePicker}
placeholder="DD/MM/YYYY"
dateFormat="DD/MM/YYYY"
showTodayButton={showTodayButton}/>
</Col>
{pristine && !!hint && (
<Col sm={6}>
<HelpBlock>{hint}</HelpBlock>
</Col>
)}
{touched && (
(error && (
<Col sm={6}>
<HelpBlock>{error}</HelpBlock>
</Col>)
) || (warning && (
<Col sm={6}>
<HelpBlock>{warning}</HelpBlock>
</Col>
))
)}
</FormGroup>
)}
const MyForm = props => {
const { error, handleSubmit, pristine, reset, submitting, fields } = props
console.debug('fields', fields) // fields is undefined
return (
<Form horizontal>
<Field
name="dateFrom"
component={renderDatepicker}
label="Date from"
hint="Earliest date for enquiry"
validate={[required, maxDate('where do I get the other date value from?')]}
/>
<Field
name="dateTo"
component={renderDatepicker}
label="Date to"
showTodayButton={true}
hint="Latest date for enquiry"
validate={[required, minDate('where do I get the other date value from?')]}
/>
</Form>
)
}
export default reduxForm({
form: 'MyForm',
})(MyForm)
I get the feeling I am missing something obvious since all the examples I have seen expect that the fields array to exist in the props.
It's also worth mentioning that the Field's validate function signature is validate : (value, allValues, props) => error [optional] so you actually have a reference to other fields values in field-level validation as well.
I believe you could do something like:
const maxDateValidationAdapter = (value, values) => maxDate(values.dateTo)(value);
// Alternatively, if maxDate() is used only in this form you can just change its signature
<Field
name="dateFrom"
component={renderDatepicker}
label="Date from"
hint="Earliest date for enquiry"
validate={[required, maxDateValidationAdapter]}
/>
See Field documentation (Props you can pass to Field => validate).
For Redux Form, use:
export default reduxForm({
form: 'MyForm', // a unique identifier for this form
validate, // <--- validation function given to redux-form
})(MyForm)
const validate = values => {
const errors = {}
// Here you can get all the fields in value object, use value.min or value.max
return errors
}
http://redux-form.com/6.4.3/examples/syncValidation/

Resources