If you are looking to learn how to validate custom lightning components forms in a flow screen then hopefully this post could shed some light on what can be accomplished and the solutions implemented around it.
So far, I found it straight forward to add a custom lightning component in a flow screen, simply specify that you are implementing the “lightning:availabelForFlowScreens” and the component becomes an available element in the flow screen.
Should appear as an option under the Custom heading of the Screen Elements.
However, adding validation for the form inputs in the lightning component with flow screens is a tricky subject with all the limitations of the “out of the box” functionalities.
My requirements are following:
- capture user information
- fields are displayed based on user inputs
- and fields are mandatory
- only when mandatory fields are completed can you proceed to the next screen
- ability to navigate back and update any fields.
So far my screen looks like per screenshot when first question is answered Yes.
Hitting next just straight goes to the next screen without any validation.
To allow us to do some sort of validation, we would use the Aura.Action attribute type. As per documentation.
An Aura.Action is a reference to an action in the framework. If a child component has an Aura.Action attribute, a parent component can pass in an action handler when it instantiates the child component in its markup.
Can’t find further documentation, but the way I understand it, in the context of flows, the flow screen acts as the parent component and we can call the function in the lightning component by declaring the attribute.
The type Aura.action returns the following object.
isValid: Boolean – stops the flow from going to the next screen.
errorMessage: String – custom error message.
To make this work we also need to add the action handler init. The ”Next” button on flow screens calls the action handler but only on init. (Why on init only? I still don’t fully understand.) Hitting next forces the lightning component to rerender and call init, from init we can set the validate object.
From your controller.js Set the component “v.validate”.
Without any inputs, if I hit Next.
Yey! So far validation works!
Let’s add some more validation logic.
When I answer questions and leave some blank. I get several issues with this validation.
- when the component rerenders
- any custom hide/show logic would be lost
- any inputs are lost
- validation error location is at the bottom of the screen
- you can only show one error at a time
To get around these limitations, I ended up building some custom validation handling, with a combination of flow variables to persist data, design attributes for input/output, sessionStorage to track missing fields inputs, and fieldCustomValidity and if you have date fields or combobox you may need to use afterRender calls.
First update the .design file for the input fields that needs to persists. To keep it easy we use one attribute per field.
Next create flow variables for each attribute and checkbox is available for input and output set to true.
Here is the final attributes
Next assign each to the custom lightning component input and output.
Now for the new validation logic. First I created an array for mandatoryFields. For each field required I add aura:id to the array.
Next I iterate to the array of fields and check if it has been populated with a value. For each missing value I again add to a new array called missingFields.
Next I check the length of the missing fields and I store the information in a sessionStorage.
SessionStorage is like localStorage but it gets cleared up when the session ends. (will cover storing of data locally on another topic)
Then I call the return statement setting isValid to false and an empty errorMessage(this property is required to display errors on the page).
So when Next action is called, it runs the init and sets the sessionStorage.
Note that I’m using the renderer. As adding a date field threw me off a little as the DOM is not yet ready after init and you are trying to access them checking for missing inputs. Solution was to put in the afterRender. But if you only have the basic input fields, you can have the code in the init as well.
I call helper method which displays the error by reading the sessionStorage for missing fields and I set the fieldCustomValidity.
And my flow is looking sharper, I am prompted for incomplete fields and I can move to next when complete and go back and update if I need to.
Update: When you try to run the flow again or open a new tab the session from the flow still persists. To fix this we would need a new action that calls an Aura or LWC Component at the before the flow launches that clears the storage.
Code for this is posted on my github repo.
I’ll be posting a video tutorial as well soon. Stay tuned.
Hope someone find this post useful. Happy coding!