You want to call Form OnLoad multiple times? Don’t!
I was reading about a blogpost to trigger the Form OnLoad multiple times. This should happen after the data was saved and/or refreshed.
Why would you want this? Usually, the Form OnLoad contains logic to change the UI, like hiding or showing controls based on the data. So, when the data is reloaded you want to re-evaluate this logic.
The proposed solution was to trigger the Form OnLoad again when the ModifiedOn changed or by using the addOnPostSave. Both solutions sound ok, until you realize that the Form OnLoad can contain initialization logic that you only want to run once, like registering event handlers.
The blogpost explains how to fix this problem by keeping the state when the Form OnLoad has already been executed. A satisfactory solution, but there is even a better one.
Form OnLoad event is meant to only run once
Form OnLoad event is actually not meant to run multiple times. The Form OnLoad event by default only runs in the following scenarios:
- On initial page load.
- After a new record is first saved (created).
A perfect location to set up event handlers and other things need to be initialized, that only need to run once in the lifecycle of a form.
It isn’t the perfect place to trigger UI changes when data is loaded, for example after saving.
Enter Data OnLoad event
There is an event that is more suited for this, but very unknown. This is because it is almost never used in code examples, not even by Microsoft. This is the Data OnLoad event!
The Data OnLoad occurs whenever form data is loaded, specifically:
- On initial page load (after Form OnLoad).
- When the page data is explicitly refreshed using formContext.data.refresh method.
- When the data is refreshed on a page on saving a record, if there are any changes.
We can hook this event up in the Form OnLoad like:
function onFormLoad(executionContext) {
const formContext = executionContext.getFormContext();
formContext.data.addOnLoad(onDataLoad);
// other init actions...
}
function onDataLoad(executionContext) {
const formContext = executionContext.getFormContext();
// actions to execute every time data is loaded...
}
Separating of concerns
When we are using both Form OnLoad and Data OnLoad we can separate the concerns very explicitly. The solution from the blogpost would be something like this:
(function (exports) {
'use strict';
function onFormLoad(executionContext) {
const formContext = executionContext.getFormContext();
formContext.data.addOnLoad(onDataLoad);
formContext.getAttribute('name').addOnChange(onNameChange);
formContext.getControl('parentaccountid').addPreSearch(filterParentAccountByWebsiteUrl);
}
function onDataLoad(executionContext) {
const formContext = executionContext.getFormContext();
formContext.getAttribute("name").fireOnChange();
}
function onNameChange(executionContext) {
const formContext = executionContext.getFormContext();
const name = formContext.getAttribute("name").getValue();
if (name == null) return;
const nameContainsLock = name.includes("lock");
formContext.getControl('parentaccountid').setDisabled(nameContainsLock);
}
function filterParentAccountByWebsiteUrl(executionContext) {
const formContext = executionContext.getFormContext();
const url = formContext.getAttribute("websiteurl").getValue();
if (url == null) return;
const filter = `<filter type="and"><condition attribute="websiteurl" operator="eq" value="${url}" /></filter>`;
formContext.getControl('parentaccountid').addCustomFilter(filter);
}
exports.onFormLoad = onFormLoad;
})(this.Account = this.Account || {});
Hopefully more examples will pop up on the internet to spread the Data OnLoad event :-).