HomeBlogDevelopment & IntegrationsMicrosoft Partner · Charlottesville, VA
Development & Integrations

How to Refresh a Dynamics 365 Subgrid with JavaScript

Refresh a Dynamics 365 subgrid with Microsoft’s supported JavaScript API. refresh() supports 2 grid types; learn event timing, checks, and practical tests.

Dynamics 365 GroupSeptember 5, 20259 min read← All posts
How to Refresh a Dynamics 365 Subgrid with JavaScript

TL;DR

  • Get formContext from the event’s executionContext.
  • Find the subgrid by its control name, then call gridControl.refresh().
  • Check for a missing control because forms, roles, and app variants can expose different controls.
  • Refresh after the related data operation succeeds, not on an arbitrary timer.
  • Use refreshRibbon() only when command-bar rules need re-evaluation; it does not reload grid records.

To refresh one Dynamics 365 subgrid, retrieve its grid control from formContext and call refresh(). Microsoft documents that method for both read-only and editable grids. It updates the grid’s records without forcing a full form reload.

I use this pattern after a related record is created, updated, associated, or removed. The important details are the subgrid’s configured control name and the timing of the call. If either is wrong, valid JavaScript can appear to do nothing.

How do you refresh a Dynamics 365 subgrid?

Refresh a subgrid by first getting the current form context, retrieving the grid control by name, checking the result, and calling refresh(). Microsoft’s grid control refresh reference confirms that the same call supports the platform’s 2 grid types: read-only and editable.

function refreshContactsSubgrid(executionContext) {
  const formContext = executionContext.getFormContext();
  const gridControl = formContext.getControl("Contacts");

  if (!gridControl) {
    console.warn('Subgrid control "Contacts" was not found on this form.');
    return;
  }

  gridControl.refresh();
}

This is the supported core pattern. Register refreshContactsSubgrid on the appropriate form event and select Pass execution context as first parameter in the handler properties.

Step 1: use the subgrid control name

Open the model-driven form designer, select the subgrid, and copy its Name property. That value may differ from the table, relationship, section, or view name.

Microsoft’s formContext.getControl reference states that an incorrect or unavailable name returns null. The guard in the example prevents a script error when a role-specific form does not contain the control.

Step 2: get the current form context

For a form event, use executionContext.getFormContext(). Do not add new code that relies on the global Xrm.Page object. Microsoft documents Xrm.Page as deprecated and recommends the event’s form context for current scripts.

The form context is scoped to the event in which it was supplied. Keep the lookup and refresh close to that event, especially when asynchronous operations are involved.

Step 3: call refresh on the control

Call refresh() on the control returned by getControl. You do not need getGrid() to refresh its records.

gridControl.refresh();

Use getGrid() when you need row information, such as selected rows or the total records matching the view. Microsoft distinguishes the grid control from the Grid object that exposes row data.

When should you refresh a subgrid?

Refresh only after an action could have changed the records or values shown in that subgrid. Good triggers include a successful create, update, associate, disassociate, or delete operation. Avoid refreshing every grid on every form event because each refresh requests data and can make a busy form feel less responsive.

Trigger Refresh approach Reason
Related record operation succeeds Refresh the affected subgrid The displayed query result may have changed
Parent record save completes Refresh only if save logic changes related data Ordinary field saves may not affect the grid
User selects a custom Refresh command Refresh the named control Gives the user an explicit recovery action
Grid finishes loading Run dependent logic in its OnLoad handler The rows are available at that point
Fixed timeout expires Avoid as the primary trigger Network and server timing vary

When I configure automation that creates related records, I call the refresh from the operation’s success path. I do not use a five-second delay as a substitute for knowing when the operation completed. A timer can fire too early on a slow request and adds unnecessary delay on a fast one.

If you need to refresh the entire record rather than one grid, use the separate form-data pattern explained in how to refresh a Dynamics 365 form with JavaScript. The two operations solve different problems.

How do you handle subgrid load timing?

Use the subgrid OnLoad event when later logic depends on the grid having finished loading. The grid may not be ready at the same moment as the parent form. Microsoft provides addOnLoad and removeOnLoad for this lifecycle; avoid repeated registration when a form handler can run more than once.

const ContactsGridHandlers = (() => {
  let isRegistered = false;

  function register(executionContext) {
    if (isRegistered) return;

    const formContext = executionContext.getFormContext();
    const gridControl = formContext.getControl("Contacts");

    if (!gridControl) return;

    gridControl.addOnLoad(onGridLoad);
    isRegistered = true;
  }

  function onGridLoad(executionContext) {
    const gridControl = executionContext.getEventSource();
    const totalRecords = gridControl.getGrid().getTotalRecordCount();
    console.debug(`Contacts subgrid loaded with ${totalRecords} matching records.`);
  }

  return { register };
})();

Register ContactsGridHandlers.register on the form OnLoad event. Microsoft’s addOnLoad documentation says the platform passes the execution context to the grid handler automatically.

The example logs a diagnostic value. In production, replace that line with the small piece of logic that truly depends on loaded rows. Do not call refresh() unconditionally inside the grid’s own OnLoad handler. That can produce a refresh loop because each completed refresh raises OnLoad again.

How do you refresh from a command button?

A command button should use the context passed by the command definition, not assume it received a form event’s execution context. For a form command, pass PrimaryControl; for a grid command, pass SelectedControl. Microsoft documents both parameters in its ribbon action context guidance.

For a command placed on the form, pass PrimaryControl and use it as the form context:

function refreshContactsFromCommand(primaryControl) {
  const formContext = primaryControl;
  const gridControl = formContext.getControl("Contacts");

  if (!gridControl) {
    return;
  }

  gridControl.refresh();
}

For a command on the subgrid itself, SelectedControl already supplies the grid context:

function refreshSelectedGrid(selectedControl) {
  if (selectedControl) {
    selectedControl.refresh();
  }
}

Do not mix these signatures. primaryControl.getControl("Contacts") is correct for a form command. selectedControl.refresh() is correct when the command passes the selected grid control.

What is the difference between refresh() and refreshRibbon()?

Use refresh() to reload records and refreshRibbon() to re-evaluate command-bar rules for that grid. They change different parts of the interface. A data refresh does not guarantee that custom enable or display rules are recalculated, and a ribbon refresh does not request current grid records.

function refreshGridAndCommands(executionContext) {
  const formContext = executionContext.getFormContext();
  const gridControl = formContext.getControl("Contacts");

  if (!gridControl) return;

  gridControl.refresh();
  gridControl.refreshRibbon();
}

Call both only when the operation changes both record data and the values used by command rules. Microsoft’s refreshRibbon() reference defines it specifically as refreshing rules for the grid control.

Why does a Dynamics 365 subgrid fail to refresh?

A failed refresh is usually a control lookup, event registration, timing, or data-query issue. Start by confirming the function runs and getControl returns the expected grid. Then verify that the changed record actually matches the subgrid’s relationship, view filter, user permissions, and current parent record.

The control is null

Check the subgrid’s Name property in every relevant form. A control present on the main Account form may be absent or renamed on another form selected by a security role.

const gridControl = formContext.getControl("Contacts");
console.debug({ gridControl });

If the value is null, fix the configured control name or handle the form variant. Do not replace the guard with a broad try...catch that hides the configuration error.

The function never runs

Confirm that the JavaScript web resource is added to the form library and that the handler uses the correct function name. For form events, enable Pass execution context as first parameter. Publish the solution changes, reload the app, and use a breakpoint or temporary console message to prove the handler runs.

For more examples of current form scripting patterns, see these Dynamics 365 JavaScript examples.

The grid refreshes but the record is missing

A refresh reruns the subgrid’s query; it does not make an unrelated record qualify for that query. Check the relationship, active view, owner or business-unit filters, record state, and the user’s read privileges. Also confirm that the create or update request completed successfully before refreshing.

The script causes repeated network requests

Look for refresh() inside the same grid’s OnLoad handler. Because the load handler runs after a refresh, an unconditional refresh can trigger another load. Add a real state condition or move the refresh to the event that changes the underlying data.

How do you test subgrid refresh code?

Test the exact form, app, role, and triggering action used in production. Verify both the expected data change and the absence of extra requests or console errors. A passing test proves that the visible grid reflects the server query; it does not by itself prove a broader productivity or revenue outcome.

Use this targeted checklist:

  1. Open the expected model-driven app and form variant.
  2. Confirm the subgrid loads for the test user’s security role.
  3. Perform the create, update, associate, or delete action that should change the grid.
  4. Confirm the refresh handler runs once.
  5. Verify the expected record appears, changes, or disappears without a full page reload.
  6. Confirm view filters, sorting, editable-grid behavior, and command states remain correct.
  7. Check the browser console and network panel for errors or repeated requests.
  8. Repeat with a form variant that does not contain the control to verify the null guard.

For implementations that need broader form scripting, automation, and governance, our Power Platform consulting service covers model-driven app design and production hardening.

What subgrid refresh patterns should you avoid?

Avoid deprecated global context, guessed delays, unguarded control access, and whole-form refreshes used to solve a one-grid problem. These patterns may appear to work in a narrow test but become unreliable across form variants, network conditions, and app updates. Keep the implementation attached to a supported event and the smallest affected control.

  • Do not use Xrm.Page in new form scripts.
  • Do not use parent.Xrm.Page for ordinary form events.
  • Do not call formContext.data.refresh() when only a subgrid changed.
  • Do not use setTimeout to guess when a server operation finished.
  • Do not call refresh() from the same grid’s OnLoad handler without a guard condition.
  • Do not confuse the subgrid control name with a table, relationship, or view name.
  • Do not assume every security-role form contains the same subgrid.
  • Do not use refreshRibbon() when you need to reload records.

The reliable implementation is small: receive the correct context, retrieve the intended control, guard against null, and refresh after the data-changing operation succeeds.


Frequently Asked Questions

How do I refresh a subgrid in Dynamics 365 with JavaScript?

Get the form context from the execution context, retrieve the subgrid control by its configured name, check that the control exists, and call refresh() on that control.

Does subgrid refresh reload the entire Dynamics 365 form?

No. Calling refresh() on the grid control requests fresh data for that grid. It does not perform a full page reload or refresh every field on the form.

Why does formContext.getControl return null for my subgrid?

The value passed to getControl must be the subgrid control name configured on the form, not the table display name, relationship name, or view name. The control may also be unavailable on a different form variant.

Should I use Xrm.Page to refresh a Dynamics 365 subgrid?

No for new code. Microsoft has deprecated Xrm.Page. Form event handlers should receive the execution context and call executionContext.getFormContext(). Command actions receive their context through a command parameter.

Is refreshRibbon() the same as refresh()?

No. refresh() reloads the grid data. refreshRibbon() re-evaluates the grid command bar rules. Call each method only for the state that actually changed.


Daniel Harper

Contributor, Dynamics 365 Group

This 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.

Dynamics 365JavaScriptmodel-driven appssubgridClient API

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