650 words
3 minutes
To build an Entity Metadata Lookup in Dynamics 365 CE using Web resources(Iframe)

To build an Entity Metadata Lookup in Dynamics 365 CRM using Web Resources, using below:#

  • Use Xrm.Navigation.navigateTo for dialog to display list of Entities
  • Passing the target CRM field dynamically via form parameters (data=fieldName=...)
  • Retrieve entity metadata using Webapi call to /api/data/v9.2/EntityDefinitions
  • Filter the retrieved result using filter
  • Write the selection back to the correct CRM field using window.top.globalformContext

To build an Entity Metadata Lookup in Dynamics 365 CE using Web resources(Iframe) with Dynamic Field Binding#

In this tutorial, I will walk you through the steps to build a custom entity metadata lookup using HTML + JavaScript web resources in Dynamics 365 CE. This component allows users to search for and select an entity (table) from metadata and write the selected logical name to any form field dynamically.


File Name and Usage#

FilePurpose
lookup.htmlEmbedded on the CRM form to show the selected entity and button to open dialog
lookup.jsTo Open dialog and to return selected entity
lookup_dialog.htmlModal dialog to show entity list from Webapi
lookup_dialog.jsLogic to Load metadata, filter, and to return selected entity

Folder Structure#

WebResources/
├── lookup.html
├── lookup.js
├── lookup_dialog.html
└── lookup_dialog.js

lookup.html to show the selected entity and the button to open lookup dialog#

<!DOCTYPE html>
<html>
<head>
  <title>Entity Metadata Lookup</title>
  <script src="lookup.js"></script>
</head>
<body onload="initializeLookup()">
    <div class="label">Entity Name</div>
    <div class="container">
      <div id="selected-entity">No entity selected</div>
      <button onclick="clearData()" id="clear-button">X</button>
      <button onclick="openLookupDialog()">Select Entity</button>
    </div>
</body>
</html>

lookup.js to handle logic to display the crm field value and to display the selected entity based on the selection returned from the dialog#

let selectedEntityField = "";
let formContext = null;

function initializeLookup() {

  const params = new URLSearchParams(window.location.search);
  const rawData = decodeURIComponent(params.get("data") || "");
  const parsedData = Object.fromEntries(new URLSearchParams(rawData));
  selectedEntityField = parsedData.fieldName;

  var interval = setInterval(() => {
    if (window.top.OrchestratorFormContext) {
      clearInterval(interval);
      formContext = window.top.OrchestratorFormContext;
      if (formContext?.getAttribute(selectedEntityField)) {
        document.getElementById("selected-entity").innerText = formContext.getAttribute(selectedEntityField).getValue();
      }
    }
  }, 2000);
}

function clearData() {
  if (formContext && formContext?.getAttribute(selectedEntityField)) {
    formContext.getAttribute(selectedEntityField).setValue(null);
    document.getElementById("selected-entity").innerText = "";
  }
}
function openLookupDialog() {
  if (selectedEntityField === "") {
    alert("Please select an entity field.");
    return;
  }
  const pageInput = {
    pageType: "webresource",
    webresourceName: "anuprakash_entity_lookup_/lookup_dialog.html",
    data: ""
  };

  const navigationOptions = {
    target: 2,
    width: 700,
    height: 400,
    position: 1
  };

  parent.Xrm.Navigation.navigateTo(pageInput, navigationOptions).then((result) => {
    if (result && result.returnValue?.selectedEntity) {
      debugger;
      const entity = result.returnValue;
      document.getElementById("selected-entity").innerText = entity.selectedEntity.logicalName;

      if (formContext?.getAttribute(selectedEntityField)) {
        formContext.getAttribute(selectedEntityField).setValue(entity.selectedEntity.logicalName);
      }
    }
  });
}

lookup\_dialog.html to display the entity metadata results as html table#

<!DOCTYPE html>
<html>
<head>
  <title>Select Entity</title>
  <script src="lookup_dialog.js"></script>
</head>
<body onload="initializeDialog()">
    <input
      type="text"
      id="searchBox"
      placeholder="Search entities..."
      oninput="filterEntities()"
    />
    <table border="1" id="entityTable" class="floating-header">
      <thead>
        <tr>
          <th>Display Name</th>
          <th>Logical Name</th>
        </tr>
      </thead>
      <tbody id="entityTableBody"></tbody>
    </table>
</body>
</html>

lookup\_dialog.js to handle logic to display the entity metadata results and to return the selected entity on click of table row#

let allEntities = [];

function initializeDialog() {
  fetchEntities().then(data => {
    allEntities = data;
    renderTable(allEntities);
  });
}

async function fetchEntities() {
  const url = parent.Xrm.Utility.getGlobalContext().getClientUrl() + "/api/data/v9.2/EntityDefinitions?$select=LogicalName,DisplayName,IsCustomEntity";

  const response = await fetch(url, {
    headers: {
      "OData-MaxVersion": "4.0",
      "OData-Version": "4.0",
      "Accept": "application/json",
      "Content-Type": "application/json; charset=utf-8",
      "Prefer": "odata.include-annotations=*"
    },
    credentials: "same-origin"
  });

  const json = await response.json();
  return json.value.map(e => ({
    logicalName: e.LogicalName,
    displayName: e.DisplayName?.UserLocalizedLabel?.Label ?? e.LogicalName
  }));
}

function renderTable(entities) {
  const tbody = document.getElementById("entityTableBody");
  tbody.innerHTML = "";

  entities.forEach(entity => {
    const tr = document.createElement("tr");
    tr.innerHTML = `<td>${entity.displayName}</td><td>${entity.logicalName}</td>`;
    tr.style.cursor = "pointer";
    tr.onclick = () => selectEntity(entity);
    tbody.appendChild(tr);
  });
}

function filterEntities() {
  const search = document.getElementById("searchBox").value.toLowerCase();
  const filtered = allEntities.filter(item =>
    item.displayName.toLowerCase().includes(search) ||
    item.logicalName.toLowerCase().includes(search)
  );
  renderTable(filtered);
}

function selectEntity(entity) {
  window.returnValue = { selectedEntity: entity };
  window.close();
}

Add lookup.html to Your Form#

  1. Go to the CRM form editor

  2. Add lookup.html as a Web Resource

  3. In the “Custom Parameters (data)” box, set:

    fieldName=anup_entityname

💡Replace anup_entityname with the schema name of your CRM field.


Conclusion and Output Video#

StepAction
1lookup.html is added to form and receives fieldName=...
2lookup.js reads that field name dynamically
3Opens lookup_dialog.html using Xrm.Navigation.navigateTo()
4User selects entity from metadata table
5Dialog closes and returns { id, name }
6lookup.js sets CRM field value using window.top.globalformContext

Screenshot of the Custom Control#


GitHub Repository to the Code and Solution#

You can find the full code here:
👉 anu-prakash-dev/d365-ce-entity-metadata-lookup


To build an Entity Metadata Lookup in Dynamics 365 CE using Web resources(Iframe)
https://crmte.ch/posts/entitylookup/
Author
Anu Prakash S I
Published at
2025-06-20
License
CC BY-NC-SA 4.0