问题
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?
I have tried to append fetchXML
to form grid vie JS, but no success there by two reasons:
1) FetchXML
is not valid, because of twin-linked entity search, i suppose. If it is not supported, the whole approach is wrong.
2) Even if leaving filtering only for one entity, d365 drops an error Invalid FetchXML
on opening Contact form. FetchXML validators
are stating opposite.
Estimated full fetchXML (not valid):
<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="currentContactIdInsertedViaJs" />
</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="currentContactIdInsertedViaJs" />
</filter>
</link-entity>
</link-entity>
</link-entity>
</link-entity>
</link-entity>
</link-entity>
</entity>
</fetch>
JS code with single entity filter:
function filterTrainings(executionContext) {
var formContext = executionContext.getFormContext();
var guid = Xrm.Page.data.entity.getId();
var fullname = formContext.getAttribute("fullname").getValue();
//var fullName = formContext.getAttribute("fullname_d").getValue();
var fetchXML = "<fetch>";
fetchXML+= "<entity name='new_schulungstyp'>";
fetchXML+= "<attribute name='new_name' />";
fetchXML+= "<attribute name='createdon' />";
fetchXML+= "<attribute name='new_schulungstypid' />";
fetchXML+= "<attribute name='new_typ' />";
fetchXML+= "<attribute name='new_intervall' />";
fetchXML+= "<order attribute='createdon' descending='false' />";
fetchXML+= "<filter type='and'>";
fetchXML+= "<condition attribute='statecode' operator='eq' value='0' />";
fetchXML+= "</filter>";
fetchXML+= "<link-entity name='new_new_schulungstyp_new_azttigkeit' from='new_schulungstypid' to='new_schulungstypid' visible='false' intersect='true'>";
fetchXML+= "<link-entity name='new_azttigkeit' from='new_azttigkeitid' to='new_azttigkeitid' alias='aj'>";
fetchXML+= "<link-entity name='new_new_profil_new_azttigkeit' from='new_azttigkeitid' to='new_azttigkeitid' visible='false' intersect='true'>";
fetchXML+= "<link-entity name='new_profil' from='new_profilid' to='new_profilid' alias='ak'>";
fetchXML+= "<link-entity name='new_contact_new_profil' from='new_profilid' to='new_profilid' visible='false' intersect='true'>";
fetchXML+= "<link-entity name='contact' from='contactid' to='contactid' alias='al'>";
fetchXML+= "<filter type='and'>";
fetchXML+= "<condition attribute='contactid' operator='eq' value='"+guid+"' />";
fetchXML+= "</filter>";
fetchXML+= "</link-entity>";
fetchXML+= "</link-entity>";
fetchXML+= "</link-entity>";
fetchXML+= "</link-entity>";
fetchXML+= "</link-entity>";
fetchXML+= "</link-entity>";
fetchXML+= "</entity>";
fetchXML+= "</fetch>";
var grid = formContext.getControl("relatedTrainings");
if (grid == null) {
setTimeout(function () {
filterTrainings(executionContext);
}, 2000);
return;
} else {
grid.getGrid().setParameter("fetchXml", filterTrainings); //set the fetch xml to the sub grid
console.log("refresh............")
}
}
回答1:
Managed to figure that one out. I am getting all required ID's that should be displayed in subgrid by subsequently sending get requests. Most important here is to manage async nature of promises. Then I build a filter that forces subgrid to show only entities, that are in related ID collection
Posting my 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 => `<value>${val}</value>`);
console.log(values);
xml = `<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">
<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="new_schulungstypid" operator="in">${values.join('')}</condition>
</filter>
</entity>
</fetch>`;
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));
}
}
来源:https://stackoverflow.com/questions/60277126/d365-display-deeply-related-information-on-a-form-in-subgrid