MrWolfZ/ngrx-forms

Async validation, but synchronous?

Zonnex opened this issue · 2 comments

Hi, first of all, thank you for this great library!

TLDR: Do you have a suggestion for how to do form validation based on feature flags in database?

I found myself in a situation that seems unsupported by ngrx and ngrx-forms, and would like to hear if you have any suggestion how to tackle this.

In this project I'm working on, there are multiple versions of a complex form depending on which region you are.
Some fields are required for all, some are optional for all.
However, some fields are conditionally required based on settings, and some are even required if a certain checkbox is selected, and this checkbox might not exist for some regions.
For example. A region might have a checkbox, and if that checkbox is selected, then a certain textarea is required.
I would really like to enable testing for this reducer, but I can't figure out a decent way to accomplish this.

Currently we have a feature slice (core) that contains the settings for the region when you are logged in, because we have other sections on the site that need to know whether or not things should be rendered.
The complex form lives in a separate slice, simplified we can imagine it like this but in reality it's more complex:

core: {
  region: {
    settings: {
      ...
    }
  }
},
order: {
  orderFormState: {
    form: FormGroupState<T>
  },
  otherThingsHere: {
    ...
  }
}

I have some thoughts on what I can do, but neither is really that great.
One way is to duplicate the region settings into orderFormState, because it seems that I can't access the global state in the feature reducer. Based on this issue, it seems like a bad idea to do and it makes sense, but I'm still stuck with trying to do validation based on "global settings". Duplicated settings might be the least bad way to accomplish this.
This way I might be able to get validation synchronously and it should be fairly easy to test this then. Ideally the forms initial value would be created using createFormGroupState based on the global settings, but I can't think of a way to do that, so that might not be feasible.
Another way is to solve this using async validation, and provide the extra validation rules as an effect. The sad part with this is that validation rules will be split between the reducer, and the effect.

Any assistance here would be appreciated.

Yeah, this is a tricky situation. I would also go with duplicating the state into the form state, but keep it minimal. For example, when creating the form state, do you really need the full region state or can everything be encapsulated in the action that populates the region state? With the action, you wouldn't even need to keep the state, just use it in the action handler. Reacting to the same action in different reducers is a well established pattern in redux/ngrx.

For conditional validation you could set user defined properties on the form controls that need to be conditional. This could also be done as a result of the action which initializes the form state. Then in your validation function just check that property and either apply the validation or not.

Hi, sorry for slow reply.

I went something similar to the suggested approach, that we now have an action that "initializes" the form after creation. This action carries the settings and populates userDefinedProperties with metadata that we can use to validate and conditionally render controls in the form. Great suggestion! We can now test our form logic in a way that greatly helps us ensure the form is working as intended. Maybe there's a better way, but this works well enough for us.

Thanks for your quick reply, and thanks for making this library available for us!