Closed jetpack3331 closed 5 years ago
Hi. Thanks for a question. If I understood your question correctly, you want to provide an application-wide rule
or asyncRule
validation rules for all inputs.
Field.props.rule
There is no need to provide this application-wide. This prop is designed to be explicitly set on individual inputs to provide per-instance validation. Application-wide synchronous rules can be defined in a validation schema and provided to either FormProvider
or Form
components:
const rules = {
type: {
// Applies to all inputs [type="email"]
email: ({ value }) => validate(value),
}
}
// To affect the entire application
<FormProvider rules={rules}>...</FormProvider>
// To affect a specific form
<Form rules={rules}>...</Form>
Field.props.asyncRule
Async rules are designed to be instance-specific and cannot be declared application-wide using plain library's API. Original motivation for this was a low level of reusability of async validation functions, as they seem to be tightly coupled with each individual input.
Perhaps, we can revisit this design limitation in the next version of react-advanced-form
. Thinking of it now, I don't see any harm in defining general async validation rules (in the end value
and other things are parametric anyway).
That doesn't mean you cannot provide them application-wide at the moment. You can use custom React context and teach your fields to subscribe to that context, prefilling the value of asyncRule
of each input instance.
// pseudo-code
const AsyncContext = React.createContext({
type: { email: async ({ value }) => await validate(value) }
})
// application root
<AsyncContext.Provider>
{/* your app */}
</AsyncContext.Provider>
// Input.js
const Input = (props) => {
return (...) // nothing unusual here
}
export default createField({
mapPropsToField: ({ props, fieldRecord }) => {
return {
...fieldRecord,
// figure out a logic to grab relevant rule resolver from context.
// Using "mapPropsToField" you can set the value of "asyncRule"
// of all instances of Input created.
asyncRule: getRelevantRule(AsyncContext)
}
}
})(Input)
Let me know if these suggestions are helpful.
These rules i know and the schema :)
But i want in the args to be these properties fieldProps, fields, form
when i'm using the resolver function in the rules for the FormProvider or for the Form. Now there is only value
prop but we are using some selects for countries and i need to apply the rules based on the selected value in this Select.
Because we have looooot of forms and inputs and i don't want to add these rules specially in all of these inputs. I want to make it smarter and easier in the one place. Which can be FormProvider.
Okay, I think I'm slowly getting it. Could you please include an example of what you are talking about?
The way I understand it now, is that some resolver is not given enough parameters.
Of course
<Form={{
extend: true,
type: ({ value, formFields, form }) => {
// Here i want to make a clever rule for form based on the value from form\
// also if only contain field like formFields['countryISO']
// Then i want set some rules based on this selected value for this form
}
}}>
{children}
</Form>
Your usage of validation schema is incorrect: the type
selector accepts the map of { [fieldName]: resolver }
, but you provide resolver function right away.
If you target a specific field you can base its resolver logic on other fields:
const rules = {
extend: true,
type: {
// provide the type of a field
email: ({ value, fields }) => {
return fields.countryISO.value === 'FR' ? validateOne(value) : validateTwo(value)
}
}
}
<Form rules={rules}>{...}</Form>
This approach is recommended if all the dependencies for a validation resolver live within the form's scope (in a field state, fields, or form).
The very same principle applies to
name
selectors. You can learn more about the Validation schema in the documentation.
When the dependencies for a resolver logic live outside the form (i.e. not present in field, fields, or form, but acquired from elsewhere—store, other components, etc.), I would recommend to keep validation schema in some global state container (i.e. Redux), and communicate with it via Flux pattern. Subscribe a Form or FormProvider component to the schema from the store and it will apply a different schema once it's updated in the store.
import React from 'react'
import { connect } from 'react-redux'
import { FormProvider } from 'react-advanced-form'
const App = (props) => (
<FormProvider rules={props.rules}>
{props.children}
</FormProvider>
)
export default connect((state) => ({
rules: state.rulesInState
}))(App)
Note that in both cases you have to specify a proper field selector per library's spec.
Please, @jetpack3331, have my suggestions helped to resolve your issue?
@kettanaito yeah. I mapped it to the
Thx!
I can't find it in the documentation but it's possible somehow provide to the Form rules or to FormProvider the same resolver args to the rules?
So the resolver function will return the same parameters (not only value but even
fieldProps, fields, form
) as for the field resolver the https://redd.gitbook.io/react-advanced-form/components/field/props/rule#resolver-function ?I need to make a dependant/smart async rules for application wide forms and don't want to write a specific rule for my every input in the app.