VA Forms Library - How to work with Pre-Fill
Introduction
While working with forms is fun, there are times when users do not want to type in all of their information over and over again. This is where preFill
technology comes into play and saves the day!
What is Pre-Fill?
Pre-fill is a simple API call to Vets-API that allows the form user to have their information pre filled in the form without having to type anything. This guide will show you how to setup pre-fill inside Vets-website and how to submit a Pull Request (PR) into Vets-API Pull Requests.
Vets-Website Work
To get started, navigate to your application folder and set up some information for the pre-fill to be enabled. Let’s start with the formConfig
object, which usually lives in src/application/<your-app>/config/form.js
, where we need to add a key in the formConfig
object called prefillEnabled
.
Here is an example from the LGY/COE Form.js:
const formConfig = {
...
prefillEnabled: true,
...
}
The next thing we need to do is hook the formConfig
setting into our code, which we'll do by passing it to the SaveInProgress
component. As you can see, the property prefillEnabled
has to be set, but we're using the true
value from the formConfig
object above.
Here is an example from LGY/COE form: LGY/COE LoggedInContent SaveInProgressIntro
<SaveInProgressIntro
testActionLink
prefillEnabled={route.formConfig.prefillEnabled}
messages={route.formConfig.savedFormMessages}
formConfig={route.formConfig}
pageList={route.pageList}
downtime={route.formConfig.downtime}
startText="Request a Certificate of Eligibility"
headingLevel={2}
/>
PreFill Transformers
In the VA Forms Library there are also some helper functions created around pre-fill that could be useful to better organize pre-fill data. One of those helpers is a prefillTransformer
, which can be used to take in a pre-filled form data object, restructure it, and return the new object to be used in the form.
Here is an example from the Direct Deposit PrefillBankInformation:
/**
* Use this function in the prefillTransformer to move all bank account
* information into `view:originalBankAccount`. This is useful when using the
* PaymentView component, which will display either `bankAccount` or
* `view:originalBankAccount`.
*
* @param {object} data - All the pre-filled form data
* @returns {object} - A new pre-filled form data object after transformation.
*/
export const prefillBankInformation = (
data,
prefilledFieldNames = defaultFieldNames,
) => {
const newData = _.omit(
[
prefilledFieldNames.accountType,
prefilledFieldNames.accountNumber,
prefilledFieldNames.routingNumber,
prefilledFieldNames.bankName,
],
data,
);
const accountType = data[prefilledFieldNames.accountType];
const accountNumber = data[prefilledFieldNames.accountNumber];
const routingNumber = data[prefilledFieldNames.routingNumber];
const bankName = data[prefilledFieldNames.bankName];
if (accountType && accountNumber && routingNumber && bankName) {
newData['view:originalBankAccount'] = viewifyFields({
accountType,
accountNumber,
routingNumber,
bankName,
});
// start the bank section in 'review' mode
newData.bankAccount = { 'view:hasPrefilledBank': true };
}
return newData;
};
This snippet above is the working code that returns your new transformed object; let’s see that in action in the Education Benefits application (Form 1990s):
import { prefillBankInformation } from 'platform/forms-system/src/js/definitions/directDeposit';
...
export function prefillTransformer(pages, formData, metadata) {
...
if (bankAccount) {
const prefillBankInfo = prefillBankInformation({
...bankAccount,
bankName: bankAccount?.bankName || 'fakeBank', // so that the check in the function doesn't fail if no bankName, omitted down below
});
const prefillBankAccount = _.get(
prefillBankInfo,
'view:originalBankAccount',
{},
);
const originalBankAccount = {
...prefillBankAccount,
'view:accountType': prefillBankAccount['view:accountType']?.toLowerCase(),
'view:bankName': undefined, // need this so that prefill display messages will show correctly, remove if bankName is added
};
newFormData = {
...newFormData,
'view:originalBankAccount': originalBankAccount,
'view:directDeposit': {
bankAccount: {
...prefillBankInfo.bankAccount,
...deviewifyFields(_.omit(originalBankAccount, ['view:bankName'])),
},
},
};
}
return {
metadata,
formData: newFormData,
pages,
};
}
Vets-API Work
After getting everything setup in Vets-Website, you'll need to move on to Vets-API and get a Pull Request (PR) set up in Vets-API Pull Requests.
In this tutorial, we’ll be using this PR as a working example of what needs to be added and changed: Vets-API 12739 Pre-fill CH31 #5391 PR.
App/Models/Form_Profile.rb
The first set of changes must be made in the form_profile
file, where we need to add our application pre-fill to the ALL_FORMS
object. You can see in this example that vre_counseling
and vre_readiness
were added: Vets-API Form_Profile.rb VRE_Counseling Line.
ALL_FORMS = {
edu: %w[22-1990 22-1990N 22-1990E 22-1995 22-5490
22-5495 22-0993 22-0994 FEEDBACK-TOOL 22-10203 22-1990S 22-1990EZ],
evss: ['21-526EZ'],
hca: ['1010ez'],
pension_burial: %w[21P-530 21P-527EZ],
dependents: ['686C-674'],
decision_review: %w[20-0996 10182],
mdot: ['MDOT'],
fsr: ['5655'],
vre_counseling: ['28-8832'],
vre_readiness: ['28-1900'],
coe: ['26-1880']
}.freeze
Inside of the same file we need to adjust the FORM_ID_TO_CLASS
object and map our new pre-fill applications to their corresponding FormProfiles
: Vets-API Form_Profile.rb FormProfile line.
FORM_ID_TO_CLASS = {
'0873' => ::FormProfiles::VA0873,
'1010EZ' => ::FormProfiles::VA1010ez,
'10182' => ::FormProfiles::VA10182,
'20-0996' => ::FormProfiles::VA0996,
'21-526EZ' => ::FormProfiles::VA526ez,
'22-1990' => ::FormProfiles::VA1990,
'22-1990N' => ::FormProfiles::VA1990n,
'22-1990E' => ::FormProfiles::VA1990e,
'22-1995' => ::FormProfiles::VA1995,
'22-5490' => ::FormProfiles::VA5490,
'22-5495' => ::FormProfiles::VA5495,
'21P-530' => ::FormProfiles::VA21p530,
'21-686C' => ::FormProfiles::VA21686c,
'686C-674' => ::FormProfiles::VA686c674,
'40-10007' => ::FormProfiles::VA4010007,
'21P-527EZ' => ::FormProfiles::VA21p527ez,
'22-0993' => ::FormProfiles::VA0993,
'22-0994' => ::FormProfiles::VA0994,
'FEEDBACK-TOOL' => ::FormProfiles::FeedbackTool,
'MDOT' => ::FormProfiles::MDOT,
'22-10203' => ::FormProfiles::VA10203,
'22-1990S' => ::FormProfiles::VA1990s,
'5655' => ::FormProfiles::VA5655,
'28-8832' => ::FormProfiles::VA288832,
'28-1900' => ::FormProfiles::VA281900,
'22-1990EZ' => ::FormProfiles::VA1990ez,
'26-1880' => ::FormProfiles::VA261880
}.freeze
Now that we've set those items, we need to go make our Form_Profile page.
App/Models/Form_Profiles/va281900.rb
Following the steps above, we can now create our Vets-API Form Profiles va281900.rb FormProfile file that defines a metadata
object that holds the version, the pre-fill boolean, and the returnUrl:
# frozen_string_literal: true
class FormProfiles::VA281900 < FormProfile
def metadata
{
version: 0,
prefill: true,
returnUrl: '/veteran-information-review'
}
end
end
Config/Form_Profile_mappings/28-1900.yml
We'll need a Vets-API 28-1900 Form_Profile_Mapping file for the data that's going to be pre-filled:
veteranInformation:
fullName: [identity_information, full_name]
ssn: [identity_information, ssn]
dob: [identity_information, date_of_birth]
veteranAddress: [contact_information, address]
mainPhone: [contact_information, us_phone]
cellPhone: [contact_information, mobile_phone]
email: [contact_information, email]
Config/settings.yml
In the Vets-API settings.yml file we need to add the vre_counseling
and vre_readiness
pre-fill boolean setting:
vre_counseling:
prefill: true
vre_readiness:
prefill: true
# Settings for EVSS
evss:
prefill: true
Spec/Models/Form_Profile_Spec.rb
Finally, you need to add a test (Vets-API Form_Profile_spec.rb Test File) to ensure everything is working properly and automated tests are working as intended.
let(:v28_1900_expected) do
{
'veteranInformation' => {
'fullName' => {
'first' => user.first_name&.capitalize,
'last' => user.last_name&.capitalize,
'suffix' => user.suffix
},
'ssn' => '796111863',
'dob' => '1809-02-12'
},
'veteranAddress' => {
'street' => street_check[:street],
'street2' => street_check[:street2],
'city' => user.address[:city],
'state' => user.address[:state],
'country' => user.address[:country],
'postal_code' => user.address[:zip][0..4]
},
'mainPhone' => us_phone,
'email' => user.pciu_email
}
end
Also remember to add to the list of returns prefilled
IDs to pass that test as well: Vets-API Returns Prefilled Ids Test.
%w[
22-1990
22-1990N
22-1990E
22-1995
22-5490
22-5495
40-10007
1010ez
22-0993
FEEDBACK-TOOL
686C-674
28-8832
28-1900
26-1880
].each do |form_id|
it "returns prefilled #{form_id}" do
expect_prefilled(form_id)
end
end
Help and feedback
Get help from the Platform Support Team in Slack.
Submit a feature idea to the Platform.