Hello,
Have a requirement to show list of Unterweisung (trainings) titles in Contact's form as a subgrid. Please, look at:
Is there a way to display those using OOB functionality?
Hello Mehdi,
Managed to figure that out: the syntax for my D365 instance differs from Your's in Your post.
var trainigsControl = formContext.getControl("relatedTrainings").getGrid();
followed by
trainigsControl.setParameter("fetchXML", xml); worked for me.
Posting here full solution:
function filterTrainings(executionContext) { var formContext = executionContext.getFormContext(); var trainigsControl = formContext.getControl("relatedTrainings").getGrid(); var guid = Xrm.Page.data.entity.getId(); console.log(guid); var relatedProfiles = []; var relatedTatigkeiten = []; var relatedBetriebsmittelGruppen = []; var unterweisungTypen = []; var xml; GetRelatedProfiles() .then(() => GetRelatedTatigkeiten().then(GetTatigkeitenRelatedUnterweisungTypen).then(() => GetRelatedBetriebsmittel().then(GetBetriebsmittelRelatedUnterweisungTypen).then(buildFetchXMLAndUpdateGrid))); function buildFetchXMLAndUpdateGrid() { getUniques(unterweisungTypen); var values = unterweisungTypen.map(val => `${val}`); console.log(values); xml = ` ${values.join('')} `; console.log(xml); trainigsControl.setParameter("fetchXML", xml); trainigsControl.refresh(); return xml; } function GetRelatedProfiles() { return Xrm.WebApi.online.retrieveMultipleRecords("new_contact_new_profil", "?$select=new_profilid&$filter=contactid eq " guid).then( function success(result) { for (var i = 0; i < result.entities.length; i ) { relatedProfiles.push(result.entities[i]["new_profilid"]); } }, function (error) { console.log(error.message); // handle error conditions } ); } function getUniques(arr) { var uniques = []; arr.forEach(item => { if (uniques.indexOf(item) === -1) { uniques.push(item); } }); arr = uniques; } function GetRelatedTatigkeiten() { return Promise.all(relatedProfiles.map(profile => Xrm.WebApi.online.retrieveMultipleRecords("new_new_profil_new_azttigkeit", `?$select=new_azttigkeitid&$filter=new_profilid eq ${profile}`).then( function success(result) { for (var i = 0; i < result.entities.length; i ) { relatedTatigkeiten.push(result.entities[i]["new_azttigkeitid"]); } }, function (error) { console.log(error.message); // handle error conditions } ) )).then(() => getUniques(relatedTatigkeiten)); } function GetRelatedBetriebsmittel() { return Promise.all(relatedProfiles.map(profile => Xrm.WebApi.online.retrieveMultipleRecords("new_new_betriebsmittel_new_profil", "?$select=new_betriebsmittelid&$filter=new_profilid eq " profile).then( function success(result) { for (var i = 0; i < result.entities.length; i ) { relatedBetriebsmittelGruppen.push(result.entities[i]["new_betriebsmittelid"]) } }, function (error) { console.log(error.message); // handle error conditions } ) )).then(() => getUniques(relatedTatigkeiten)); } function GetBetriebsmittelRelatedUnterweisungTypen() { return Promise.all(relatedBetriebsmittelGruppen.map(betriebsmittel => Xrm.WebApi.online.retrieveMultipleRecords("new_new_betriebsmittel_new_schulungstyp", "?$select=new_schulungstypid&$filter=new_betriebsmittelid eq " betriebsmittel).then( function success(result) { for (var i = 0; i < result.entities.length; i ) { unterweisungTypen.push(result.entities[i]["new_schulungstypid"]); } }, function (error) { console.log(error.message); // handle error conditions } ) )).then(() => getUniques(unterweisungTypen)); } function GetTatigkeitenRelatedUnterweisungTypen() { return Promise.all(relatedTatigkeiten.map(tatigkeiten => Xrm.WebApi.online.retrieveMultipleRecords("new_new_schulungstyp_new_azttigkeit", "?$select=new_schulungstypid&$filter=new_azttigkeitid eq " tatigkeiten).then( function success(result) { for (var i = 0; i < result.entities.length; i ) { unterweisungTypen.push(result.entities[i]["new_schulungstypid"]); } }, function (error) { console.log(error.message); // handle error conditions } ))).then(() => getUniques(unterweisungTypen)); } }
Thank You for Your help, Mehdi. Very appreciated.
Hello partner,
Your JS is well written !! Maybe I miss something too. Please check in your browser's console if you find setFilterXml function. I use a debugger to get my formContext, please refer to the image below:
Update: Managed to get everything in place. The issue was that all API calls were executed asynchronously, which was leading to sending a query without ID parameter to query.
function filterTrainings(executionContext) { var formContext = executionContext.getFormContext(); var trainigsControl = formContext.getControl("relatedTrainings"); var guid = Xrm.Page.data.entity.getId(); console.log(guid); var relatedProfiles = []; var relatedTatigkeiten = []; var relatedBetriebsmittelGruppen = []; var unterweisungTypen = []; var xml; GetRelatedProfiles() .then(() => GetRelatedTatigkeiten().then(GetTatigkeitenRelatedUnterweisungTypen).then(() => GetRelatedBetriebsmittel().then(GetBetriebsmittelRelatedUnterweisungTypen).then(buildFetchXMLAndUpdateGrid))); function buildFetchXMLAndUpdateGrid() { getUniques(unterweisungTypen); var values = unterweisungTypen.map(val => `${val}`); console.log(values); xml = ` ${values.join('')} `; console.log(xml); trainigsControl.setFilterXml(xml); trainigsControl.refresh(); return xml; } function GetRelatedProfiles() { return Xrm.WebApi.online.retrieveMultipleRecords("new_contact_new_profil", "?$select=new_profilid&$filter=contactid eq " guid).then( function success(result) { for (var i = 0; i < result.entities.length; i ) { relatedProfiles.push(result.entities[i]["new_profilid"]); } }, function (error) { console.log(error.message); // handle error conditions } ); } function getUniques(arr) { var uniques = []; arr.forEach(item => { if (uniques.indexOf(item) === -1) { uniques.push(item); } }); arr = uniques; } function GetRelatedTatigkeiten() { return Promise.all(relatedProfiles.map(profile => Xrm.WebApi.online.retrieveMultipleRecords("new_new_profil_new_azttigkeit", `?$select=new_azttigkeitid&$filter=new_profilid eq ${profile}`).then( function success(result) { for (var i = 0; i < result.entities.length; i ) { relatedTatigkeiten.push(result.entities[i]["new_azttigkeitid"]); } }, function (error) { console.log(error.message); // handle error conditions } ) )).then(() => getUniques(relatedTatigkeiten)); } function GetRelatedBetriebsmittel() { return Promise.all(relatedProfiles.map(profile => Xrm.WebApi.online.retrieveMultipleRecords("new_new_betriebsmittel_new_profil", "?$select=new_betriebsmittelid&$filter=new_profilid eq " profile).then( function success(result) { for (var i = 0; i < result.entities.length; i ) { relatedBetriebsmittelGruppen.push(result.entities[i]["new_betriebsmittelid"]) } }, function (error) { console.log(error.message); // handle error conditions } ) )).then(() => getUniques(relatedTatigkeiten)); } function GetBetriebsmittelRelatedUnterweisungTypen() { return Promise.all(relatedBetriebsmittelGruppen.map(betriebsmittel => Xrm.WebApi.online.retrieveMultipleRecords("new_new_betriebsmittel_new_schulungstyp", "?$select=new_schulungstypid&$filter=new_betriebsmittelid eq " betriebsmittel).then( function success(result) { for (var i = 0; i < result.entities.length; i ) { unterweisungTypen.push(result.entities[i]["new_schulungstypid"]); } }, function (error) { console.log(error.message); // handle error conditions } ) )).then(() => getUniques(unterweisungTypen)); } function GetTatigkeitenRelatedUnterweisungTypen() { return Promise.all(relatedTatigkeiten.map(tatigkeiten => Xrm.WebApi.online.retrieveMultipleRecords("new_new_schulungstyp_new_azttigkeit", "?$select=new_schulungstypid&$filter=new_azttigkeitid eq " tatigkeiten).then( function success(result) { for (var i = 0; i < result.entities.length; i ) { unterweisungTypen.push(result.entities[i]["new_schulungstypid"]); } }, function (error) { console.log(error.message); // handle error conditions } ))).then(() => getUniques(unterweisungTypen)); } }
Built XML:
7fba9f28-d44e-e911-80dc-0017fa100b027fba9f28-d44e-e911-80dc-0017fa100b02a993610a-2c2d-e811-80db-0017fa100b02769aca6d-2c2d-e811-80db-0017fa100b02449e8a0d-97a0-e811-80dc-0017fa100b0289a86b68-0c6e-e811-80db-0017fa100b02
Currently I am building a somewhat decent fetchXML, but I have issues with trainigsControl.setFilterXml(xml);
Error:
Uncaught (in promise) TypeError: trainigsControl.setFilterXml is not a function
at buildFetchXMLAndUpdateGrid
Looks like there is a minor detail I am missing.
Mehdi, I have tried Your approach today. I focused on getting the list of ID's i need to display on my subgrid. Here is the JS sample:
function filterTrainings(executionContext) { var formContext = executionContext.getFormContext(); var guid = Xrm.Page.data.entity.getId(); var relatedProfiles = []; var relatedTatigkeiten = []; var relatedBetriebsmittelGruppen = []; var unterweisungTypen = []; function GetRelatedProfiles() { Xrm.WebApi.online.retrieveMultipleRecords("new_contact_new_profil", "?$select=new_profilid&$filter=contactid eq " guid).then( function success(result) { for (var i = 0; i < result.entities.length; i ) { relatedProfiles.push(result.entities[i]["new_profilid"]); } }, function (error) { console.log(error.message); // handle error conditions } ); } GetRelatedProfiles(); console.log(relatedProfiles); function GetRelatedTatigkeiten() { for (var i = 0; i < relatedProfiles.length; i ) { var profileId = relatedProfiles[i]; Xrm.WebApi.online.retrieveMultipleRecords("new_new_profil_new_azttigkeit", "?$select=new_azttigkeitid&$filter=new_profilid eq " profileId).then( function success(result) { for (var i = 0; i < result.entities.length; i ) { if (relatedTatigkeiten.indexOf(result.entities[i]["new_azttigkeitid"]) === -1) { relatedTatigkeiten.push(result.entities[i]["new_azttigkeitid"]); } } }, function (error) { console.log(error.message); // handle error conditions } ); } } GetRelatedTatigkeiten(); console.log(relatedTatigkeiten); function GetRelatedBetriebsmittel() { for (var i = 0; i < relatedProfiles.length; i ) { var profileId = relatedProfiles[i]; Xrm.WebApi.online.retrieveMultipleRecords("new_new_betriebsmittel_new_profil", "?$select=new_betriebsmittelid&$filter=new_profilid eq " profileId).then( function success(result) { for (var i = 0; i < result.entities.length; i ) { if (relatedTatigkeiten.indexOf(result.entities[i]["new_azttigkeitid"]) === -1) { relatedBetriebsmittelGruppen.push(result.entities[i]["new_betriebsmittelid"]) } } }, function (error) { console.log(error.message); // handle error conditions } ); } } GetRelatedBetriebsmittel(); console.log(relatedBetriebsmittelGruppen); function GetBetriebsmittelRelatedUnterweisungTypen() { for (var i = 0; i < relatedBetriebsmittelGruppen.length; i ) { var betriebsmittelGruppenId = relatedBetriebsmittelGruppen[i]; Xrm.WebApi.online.retrieveMultipleRecords("new_new_betriebsmittel_new_schulungstyp", "?$select=new_schulungstypid&$filter=new_betriebsmittelid eq " betriebsmittelGruppenId).then( function success(result) { for (var i = 0; i < result.entities.length; i ) { if (relatedTatigkeiten.indexOf(result.entities[i]["new_azttigkeitid"]) === -1) { unterweisungTypen.push(result.entities[i]["new_schulungstypid"]); } } }, function (error) { console.log(error.message); // handle error conditions } ); } } GetBetriebsmittelRelatedUnterweisungTypen(); console.log(unterweisungTypen); function GetTatigkeitenRelatedUnterweisungTypen() { for (var i = 0; i < relatedTatigkeiten.length; i ) { var tatigkeitenId = relatedTatigkeiten[i]; Xrm.WebApi.online.retrieveMultipleRecords("new_new_schulungstyp_new_azttigkeit", "?$select=new_schulungstypid&$filter=new_azttigkeitid eq " tatigkeitenId).then( function success(result) { for (var i = 0; i < result.entities.length; i ) { if (relatedTatigkeiten.indexOf(result.entities[i]["new_azttigkeitid"]) === -1) { unterweisungTypen.push(result.entities[i]["new_schulungstypid"]); } } }, function (error) { console.log(error.message); // handle error conditions } ); } } GetTatigkeitenRelatedUnterweisungTypen(); console.log(unterweisungTypen); }
GetRelatedProfiles method return expected result, while all subsequent requests are returning empty array. Surely I am missing something. May I ask for You assistance?
Separate your retrieve into two or three retrieve.
Please check the second JavaScript. You can't use link-entity in subgridControl.setFilterXml(fetchXml);
First you need to get the Ids and then use operator='in'
Forgot to mention fetchXML that I have built:
<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="true">
<entity name="new_schulungstyp">
<attribute name="new_name" />
<attribute name="createdon" />
<attribute name="new_schulungstypid" />
<attribute name="new_typ" />
<attribute name="new_intervall" />
<order attribute="createdon" descending="false" />
<filter type="and">
<condition attribute="statecode" operator="eq" value="0" />
</filter>
<link-entity name="new_new_schulungstyp_new_azttigkeit" from="new_schulungstypid" to="new_schulungstypid" visible="false" intersect="true">
<link-entity name="new_azttigkeit" from="new_azttigkeitid" to="new_azttigkeitid" alias="aa">
<link-entity name="new_new_profil_new_azttigkeit" from="new_azttigkeitid" to="new_azttigkeitid" visible="false" intersect="true">
<link-entity name="new_profil" from="new_profilid" to="new_profilid" alias="ab">
<link-entity name="new_contact_new_profil" from="new_profilid" to="new_profilid" visible="false" intersect="true">
<link-entity name="contact" from="contactid" to="contactid" alias="ac">
<filter type="or">
<condition attribute="contactid" operator="eq" value="ContactId" />
</filter>
</link-entity>
</link-entity>
</link-entity>
</link-entity>
</link-entity>
</link-entity>
<link-entity name="new_new_betriebsmittel_new_schulungstyp" from="new_schulungstypid" to="new_schulungstypid" visible="false" intersect="true">
<link-entity name="new_betriebsmittel" from="new_betriebsmittelid" to="new_betriebsmittelid" alias="ad">
<link-entity name="new_new_betriebsmittel_new_profil" from="new_betriebsmittelid" to="new_betriebsmittelid" visible="false" intersect="true">
<link-entity name="new_profil" from="new_profilid" to="new_profilid" alias="ae">
<link-entity name="new_contact_new_profil" from="new_profilid" to="new_profilid" visible="false" intersect="true">
<link-entity name="contact" from="contactid" to="contactid" alias="af">
<filter type="or">
<condition attribute="contactid" operator="eq" value="ContactId" />
</filter>
</link-entity>
</link-entity>
</link-entity>
</link-entity>
</link-entity>
</link-entity>
</entity>
</fetch>
It exceeds the limit of linked entities. Is there a way to form a better query that will match the requirement?
Will try that out and update on results. Thank You.
Hello,
Unfortunately you can't. You need some unsupported JavaScript, please check my article:
medium.com/.../dynamically-set-fetchxml-to-subgrid-on-dynamics-365-v9-uci-a4a531200e73
After the last update, the code in the article above is not working anymore. Check the last version:
medium.com/.../nice-post-50eb2eddcc3c
Hope this helps.
Daivat Vartak (v-9d...
225
Super User 2025 Season 1
Eugen Podkorytov
106
Muhammad Shahzad Sh...
106
Most Valuable Professional