Calculations order
The following describes in which order expressions and actions are (re)calculated on Modern Forms.
On form loading
- Pre-form load actions
- Initial value expressions for every field where defined
- Filter queries of lookup fields
- Required expressions where defined in order the respective component is on form
- Visible/Enabled expressions where defined in order the respective component is on form
- Tab Name expressions for all tabs
- Rendering of all form controls
- If there are sublists placeholders used in any expression, these expressions are evaluated directly after corresponding sublist is loaded
-
After-form load actions are executed after form and all sublist are loaded
On change of a field or sublist item
- Dependent Calculated expressions on form fields
--> If any calculated expressions depend on this field it is recalculated first and then 1. to 4. for that field change are executed recursively. - Dependent Tab Name expressions for all tabs
- Dependent Calculated expressions with sublists placeholders
--> If there are sublists placeholders used in expression, these expressions are reevaluated directly after corresponding sublist is changed. -
Visible/Enabled/Required expressions where defined in order the respective component is on form
On saving form
- Any pending recalculations are executed in execution order defined in "On change of a field"
- Validation in the order the form fields are on the form
-
Saving of the item for the form fields
- Saving of attachments
-
Saving of all sub items in the order of their sub lists on the form
--> If there are errors during sub items saving, main item is still added (for New form) or updated (for Edit form) but the form is not closed, user can see an error icon with tooltip error text. Sub items can be resaved after resolving errors.
Using a variable within a function placeholder
Local variables cannot be used inside any function placeholder, because the function is always evaluated before the local variable is defined.
Instead of variables in same expression, window variables that are defined in another expression can be used inside function expression placeholders.
In this case, firstly window variable is set in a Execute Code action configured as Pre-Form Load:
window.varP=2;
This window variable can be used now inside expression placeholders which will be replaced during evaluation by resulting string and afterwards the outer function expression is processed.
return [[@Web.GetFirstValueForQuery('Contacts', '<Query><Where><Eq><FieldRef Name=ID /><Value Type=Number>[[=window.varP]]</Value></Eq></Where></Query>','Title')]];
Using custom.js functions in expressions
In case if there is a need to write complex functions in separate files and use them in Modern Forms expressions with form placeholders as variables, it can be done in the following way.
Let's assume, there is a custom.js file with some function code, e.g:
function GetWantedDate(myDate)
{
var wantedDay;
wantedDay = myDate.getDay();
return wantedDay;
}
The .js script can be loaded by Execute Script action in Pre-Form Load actions.
Since load actions are executed asynchronously, the function can be unavailable when subsequent actions will be executed. If there is a need to wait for script loading, it's recommended to use jQuery.Deferred() object.
var script = document.createElement('script');
script.src = "https://m365b601773.sharepoint.com/Acounts0305/SiteAssets/custom.js";
document.head.append(script);
After this function can be called from the Modern Forms expression as a window function:
return window.GetWantedDate([[Date]]);
This approach still can cause some timing issues if script is not loaded before the expression is executed. Also it will be loaded every time the form or page is opened, which is unnecessary if your expression is not called every time.
So a better solution is to load script before running your code. For this, use the following inside a function expression:
var url = "https://m365b601773.sharepoint.com/Acounts0305/SiteAssets/custom.js";
var fileName = "custom.js";
var moduleCache = window.module;
var defineCache = window.define;
window.module = undefined;
window.define = undefined;
window.SP.SOD.registerSod(fileName, url);
window.LoadSodByKey(fileName, null, true);
window.module = moduleCache;
window.define = defineCache;
return window.GetWantedDate([[Date]]);