Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
This article helps resolve an issue caused by missing form context for internal handlers on bookable resource forms in Microsoft Dynamics 365 Field Service.
Symptoms
While creating a bookable resource in Dynamics 365 Field Service, you might receive the following error message when you select a user from a field on the form:
Cannot read properties of undefined (reading 'getFormContext')
Cause
The issue occurs because the system uses a customized form that is based on an outdated version of the bookable resource form. A change to the internal handlers for onchange
events now requires the execution context to be passed in from the form.
Resolution
Use one of the listed resolutions to ensure that the execution context is passed as the first parameter.
Important
The following resolutions assume that the script error references the Mscrm.userid_onchange
function. If the error refers to other fields or functions, such as Mscrm.accountid_onchange
or Mscrm.contactid_onchange
, adjust the steps accordingly.
Resolution 1: Update the form in Power Apps
Sign in to Power Apps and open the solution that contains the form.
Select the User field and go to the event settings.
Look for the
Mscrm.userid_onchange
event handler.If the handler doesn't exist:
- Add a new event of type On Change.
- Select the Scheduling/BookableResource/BookableResource_main_system_library.js library.
- Enter Mscrm.userid_onchange in the Function field.
- Ensure the Enabled and Pass execution context as first parameter checkboxes are selected.
If the handler exists:
- Edit the handler and ensure the Pass execution context as first parameter checkbox is selected.
Save and publish the updated form.
Resolution 2: Validate the customizations.xml file
Open the customizations.xml file from the solution associated with the customized form that shows the error in an editor.
In the
Handler
element of theMscrm.userid_onchange
function, ensure thepassExecutionContext
attribute is set to true.Republish the solution.
Resolution 3: Run a script in the browser console
To ensure this script has permission to find and update the required information, you need to run it in a browser tab that has an active session with your environment. Additionally, your user account needs permisssion to update the XML of the customized bookable resource form.
Open the environment in your browser. The following instructions use Microsoft Edge as an example.
Open DevTools by pressing F12 or navigating to ellipsis (…) > More tools > Developer tools.
Select the Console tab in DevTools and select Clear Console.
Copy and paste the following JavaScript code into the console.
const ORG = "<YOUR-ENVIRONMENT-URL>"; // for example "contoso.crm.dynamics.com" async function fixBookableResourceForms() { console.log("Starting Bookable Resource Form fetch process..."); let publishXML = false; try { const response = await fetch(`https://${ORG}/api/data/v9.2/systemforms?$filter=objecttypecode eq 'bookableresource'`); if (!response.ok) { throw new Error(`Error fetching resources: ${response.statusText}`); } const data = await response.json(); const forms = data.value; if(forms.length !== 0) { for (const form of forms) { console.log(` Checking form ${form.name} (${form.formid})...`); const formXML = form.formxml; const parser = new DOMParser(); const xmlDoc = parser.parseFromString(formXML, "text/xml"); const handlers = xmlDoc.getElementsByTagName("Handler"); const userIdHandlers = [] for (let i = 0; i < handlers.length; i++) { const handler = handlers[i]; if ( handler.getAttribute("functionName") === "Mscrm.userid_onchange" && handler.getAttribute("libraryName") === "Scheduling/BookableResource/BookableResource_main_system_library.js" ) { userIdHandlers.push(handler); } } if (userIdHandlers.length > 1) { console.warn(`Form ${form.name} (${form.formid}) has more than 1 Mscrm.userid_onchange event handlers (has ${userIdHandlers.length}).`); } else if (userIdHandlers.length === 0) { console.warn(`Form ${form.name} (${form.formid}) has 0 Mscrm.userid_onchange event handlers.`); continue; } await Promise.all(userIdHandlers.map(async handler => { if ( handler.getAttribute("functionName") === "Mscrm.userid_onchange" && handler.getAttribute("libraryName") === "Scheduling/BookableResource/BookableResource_main_system_library.js" && handler.getAttribute("passExecutionContext") === "true" ) { console.log(` Form ${form.name} (${form.formid}) has the correct Mscrm.userid_onchange event handler.`); } else if ( handler.getAttribute("functionName") === "Mscrm.userid_onchange" && handler.getAttribute("libraryName") === "Scheduling/BookableResource/BookableResource_main_system_library.js" && (handler.getAttribute("passExecutionContext") === "false" || handler.getAttribute("passExecutionContext") === null) ) { console.log(` Form ${form.name} (${form.formid}) has the Mscrm.userid_onchange event handler but the passExecutionContext attribute is not set to true. Setting it to true...`); handler.setAttribute("passExecutionContext", "true"); const serializer = new XMLSerializer(); const updatedXml = serializer.serializeToString(xmlDoc); await updateBookableResourceForms(form, updatedXml); publishXML = true; } return Promise.resolve(); })); } } else { console.log("No Bookable Resource forms found. Nothing was done"); } } catch (error) { console.error(error.message); } if(publishXML) { console.log("Publishing changes..."); await publishChanges(); publishXML = false; } console.log("Finished"); } async function updateBookableResourceForms(form, formxml) { console.log(` Updating Bookable Resource Form ${form.name} (${form.formid}) ...`); try { const reqBody = JSON.stringify({formxml: formxml}); const updateResponse = await fetch(`https://${ORG}/api/data/v9.2/systemforms(${form.formid})`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: reqBody }); if (!updateResponse.ok) { throw new Error(`Error updating form ${formid}: ${updateResponse.statusText}`); } console.log(` Form ${form.name} (${form.formid}) updated successfully.`); } catch (error) { console.error(error.message); } console.log(` Done updating Bookable Resource Form ${form.name} (${form.formid}).`); } async function publishChanges() { console.log(" Starting publish XML process..."); const publishResponse = await fetch(`https://${ORG}/api/data/v9.2/PublishXml`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{"ParameterXml": "<importexportxml><entities><entity>bookableresource</entity></entities></importexportxml>"}' }); if (!publishResponse.ok) { throw new Error(`Error publishing XML: ${publishResponse.statusText}`); } console.log(" Done publish XML process."); } // Call the function fixBookableResourceForms()
Update the
ORG
constant in the script with your environment URL, for example,contoso.crm.dynamics.com
.Run the script and review the output to confirm the updates.