Form Data OnLoad

by May 2, 2023

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 :-).

Subscribe to
The Daily Friction

A daily newsletter on automation and eliminating friction

Related Content

External authentication with Dataverse ServiceClient

For a while now we can use the new Dataverse ServiceClient that replaced the old CrmServiceClient. It has three big improvements: Works for .NET 5.0 and up (.NET Core) Uses the newer MSAL.NET instead of ADAL.NET (which is out of support) for authentication Support for...

read more

Everyone got ALM wrong in Dynamics 365 / Dataverse

For ages, we've been ferociously encouraging the integration of developer practices, such as source control and ALM, into the Dynamics 365/Dataverse realm. The ultimate truth The revered 'Master Branch' in source control, has always been the sole fountainhead from...

read more
Early-Bound Classes for .NET 4.6.2 and 6.0

Early-Bound Classes for .NET 4.6.2 and 6.0

You like to use strong types in .NET when working with Dataverse / Dynamics 365? Are you into Early-Bound Classes? Generating entity classes? You can use CrmSvcUtil for this, but I personally like to use XrmContext from Delegate to do this, because it creates smaller...

read more