TL;DR: Use
formContext.data.refresh(save)— wheresaveis a Boolean — to reload a Dynamics 365 form’s data from the server without a full page reload. ObtainformContextfrom the execution context parameter viaexecutionContext.getFormContext(). The legacyXrm.Pageobject is deprecated and must not be used in new code.
How Form Refresh Works in Dynamics 365
When you call formContext.data.refresh(), the client requests fresh record data from the Dataverse server and re-populates the form’s fields without unloading the browser page. This preserves the user’s scroll position, current tab, and—depending on the save argument—unsaved field edits while pulling updated values from the database.
The method signature, documented on Microsoft Learn, accepts a single Boolean argument:
formContext.data.refresh(save).then(successCallback, errorCallback);
Pass true and Dynamics 365 saves the current record before refreshing. Pass false and the refresh occurs without saving, which means any unsaved edits may be overwritten by the server’s copy. The method returns a Promise, so you chain .then() with a success callback and an error callback.
This method differs from formContext.data.save(), which writes the record to the database but does not reload the form. Use save() to persist changes, use refresh() to pull the latest server state, and use refresh(true) when you need both in a single call.
Accessing FormContext the Modern Way
The Xrm.Page global object is deprecated. Microsoft’s Client API deprecations guidance directs developers to pass the execution context into the event handler and call getFormContext() on it. This is the supported approach for all model-driven apps running on the Unified Interface.
Getting the Execution Context
Every form event handler can receive the execution context if you enable “Pass execution context as first parameter” in the form’s event registration properties. With that option checked, your function receives the context as its first argument:
function onFormLoad(executionContext) {
const formContext = executionContext.getFormContext();
// Access attributes, controls, and data through formContext
}
If you forget to check that box, executionContext arrives as undefined and the script fails at runtime. This is the single most common cause of broken form scripts in Dynamics 365, so add a guard at the top of every handler:
function onFormLoad(executionContext) {
if (!executionContext) {
console.error("Execution context not passed. Check 'Pass execution context as first parameter' in form properties.");
return;
}
const formContext = executionContext.getFormContext();
}
Registering the Handler in the Form Editor
To wire up your JavaScript:
- Create a JavaScript web resource and add it to your solution.
- Open the form in the form designer and select Form properties.
- Under Event Handlers, add your web resource library, choose the event (for example, OnLoad), and enter your function name.
- Check Pass execution context as first parameter.
The event registration process is described in Microsoft’s client API events reference. For deeper examples of form scripting patterns, see our collection of Dynamics 365 JavaScript examples.
When to Refresh the Form (and When Not To)
Form refresh is most valuable after server-side logic changes data the user needs to see—plugin updates, related record changes, or external integration syncs. For simple field updates where you already know the value client-side, setting the attribute directly is faster and avoids an unnecessary server round trip.
Good Use Cases
After a related record changes. If your form displays data from a parent record or a related entity—for example, pulling the parent account’s credit limit onto a contact form—a refresh ensures the displayed value matches the server after the parent record is edited elsewhere.
After server-side business logic modifies the record. Plugins, workflows, and business rules can change field values during or after a save. Calling refresh() after save() in the success callback ensures the user sees those updated values immediately.
After external data updates. If a Power Automate flow or a Power Platform integration updates the record from an external system, a refresh pulls those changes into the open form.
When a Full Refresh Is Overkill
Targeted updates are often faster and less disruptive. Instead of refreshing the entire form, set individual field values directly:
formContext.getAttribute("fieldname").setValue(newValue);
This updates the field immediately without a server round trip. Reserve data.refresh() for situations where you genuinely need data that only the server can compute. If you need to refresh an embedded grid rather than the form itself, read our guide on refreshing subgrids in Dynamics 365.
A Complete Working Example
Here is a practical scenario: a contact form must pull fresh data after the user changes the parent account lookup, because a plugin recalculates dependent fields server-side.
function onParentAccountChange(executionContext) {
if (!executionContext) return;
const formContext = executionContext.getFormContext();
// Save so server-side logic (plugins, workflows) can process the change
formContext.data.save().then(
function () {
// Refresh to display plugin-calculated values
formContext.data.refresh(false).then(
function () {
formContext.ui.setFormNotification("Data synced.", "INFO", "syncStatus");
setTimeout(function () {
formContext.ui.clearFormNotification("syncStatus");
}, 3000);
},
function (error) {
formContext.ui.setFormNotification(
"Refresh failed: " + error.message, "ERROR", "refreshError"
);
}
);
},
function (error) {
formContext.ui.setFormNotification(
"Save failed: " + error.message, "ERROR", "saveError"
);
}
);
}
Register this function on the parentaccountid field’s OnChange event with the execution context enabled. When the user selects a different parent account, the handler saves the record so the plugin runs, then refreshes to surface the recalculated values. The temporary notification tells the user the sync completed.
Best Practices for Reliable Form Refresh
Always handle errors. The .then() pattern requires both a success and an error callback. If the refresh fails—due to a network drop or a permissions issue—silently swallowing the error leaves the user looking at stale data with no warning. Always log or surface the error through formContext.ui.setFormNotification.
Do not refresh inside tight event loops. Each call to data.refresh() makes a server request. Calling it inside an OnChange handler that fires on every keystroke degrades performance and frustrates users. Gate your refresh logic so it runs at most once per meaningful action.
Do not manipulate the DOM directly. The Unified Interface re-renders form elements dynamically. Editing DOM elements with jQuery or document.getElementById is explicitly unsupported and breaks when the framework re-renders. Use the formContext API for all interactions, as described in the form context documentation.
Cache references to frequently used attributes. Storing a reference to an attribute you access repeatedly avoids repeated lookups on every call:
const creditLimitAttr = formContext.getAttribute("creditlimit");
Test in the Unified Interface. All Dynamics 365 online environments run on the Unified Interface, which has different rendering behavior from the legacy web client. Always test against the current runtime before publishing changes.
Guard against missing context. As shown in the examples above, always verify that executionContext exists before calling getFormContext(). A missing guard is the most frequent cause of “undefined” errors in production.
Troubleshooting Common Refresh Issues
Refresh problems usually trace back to one of four causes: a missing execution context, a handler that is not firing, async timing, or excessive call frequency. Here is how to diagnose each.
executionContext is undefined
The “Pass execution context as first parameter” checkbox was not selected when registering the handler. Open the form properties, find your handler, check the box, save, and publish.
The form does not refresh at all
Confirm the function is actually firing. Add a console.log at the top of your handler and check the browser developer tools console (press F12). If nothing logs, the handler is not registered or the web resource has not been published.
Stale data persists after refresh
If a plugin or workflow updates the record asynchronously, the value may not be ready when refresh() executes. The refresh pulls whatever the server has at that moment. If the async process has not completed, you get the pre-update value. In these cases, add a short delay or restructure the logic so the refresh fires after the server-side process completes.
Performance is slow
Excessive refresh calls are the usual culprit. Audit your event handlers for refresh logic that fires too frequently. Also check whether you are refreshing the entire form when a targeted setValue() would suffice.
Frequently Asked Questions
What is the difference between formContext.data.refresh() and formContext.data.save()?
save() writes the current form data to the database. refresh() reloads form data from the database to the client. Use save() to persist edits, use refresh() to pull server updates, and use refresh(true) to do both—save first, then reload.
Is Xrm.Page still supported?
Xrm.Page is deprecated. Microsoft recommends using executionContext.getFormContext() in all new and updated code. The deprecation is documented on Microsoft Learn, and existing code using Xrm.Page should be migrated.
Does formContext.data.refresh() cause a full page reload?
No. It reloads record data from the server into the current form without navigating away or reloading the browser page. The user’s position on the form and the current tab are preserved.
Can I refresh only a specific field instead of the whole form?
Yes. If you know the value client-side, use formContext.getAttribute("fieldname").setValue(value). If you need the server’s latest value for a single field, query it separately using Xrm.WebApi.retrieveRecord and then set it—data.refresh() reloads the entire record.
Where can I get help implementing custom JavaScript for my Dynamics 365 forms?
Our team builds and maintains custom Dynamics 365 form logic for organizations across industries. Learn more about our Dynamics 365 services and how we can help you automate and optimize your CRM.
Frequently Asked Questions
What is the difference between formContext.data.refresh() and formContext.data.save()?
save() writes the current form data to the database. refresh() reloads form data from the database to the client. Use refresh(true) to do both—save first, then reload.
Is Xrm.Page still supported?
Xrm.Page is deprecated. Microsoft recommends using executionContext.getFormContext() in all new and updated code, as documented on Microsoft Learn.
Does formContext.data.refresh() cause a full page reload?
No. It reloads record data from the server into the current form without navigating away or reloading the browser page. The user's form position and current tab are preserved.
Can I refresh only a specific field instead of the whole form?
Yes. If you know the value client-side, use formContext.getAttribute('fieldname').setValue(value). For the server's latest value, query it with Xrm.WebApi.retrieveRecord and set it manually.
Where can I get help implementing custom JavaScript for my Dynamics 365 forms?
Our team builds and maintains custom Dynamics 365 form logic. Learn more about our Dynamics 365 services at dynamics365group.com/services.
Daniel Harper
Contributor, Dynamics 365 GroupThis article is written by Daniel Harper for Dynamics 365 Group. Product behavior, deployment choices, and licensing can change, so confirm current Microsoft documentation before making an implementation decision.
Calculate Your Dynamics 365 Migration ROI
See how much you could save with a free, instant ROI estimate — no signup required.
Get Your Free ROI Estimate