D365: Enable Rule for button with asynchronous API request using promise
Many times, we get requirement to show/hide a button based on certain condition for which we define Enable Rule in Ribbon Workbench.
If we need javaScript code for evaluation then we use Custom Enable Rule mentioning library, method to execute, passing PrimaryControl CRM parameter and additional parameters if necessary.
Sometimes, the evaluation is done real time(based on the logic written) and we return true/false based on which the button remains visible/hidden. At times, we need to make additional API request which is asynchronous in nature e.g. show/hide button based on security role and in this case the result of the method/operation doesn’t affect the visibility of the button.
In this post, we’ll see how we can use promise to fix this issue and the scenario that we’ll take is hide Delete button on Document subgrid if the logged in user doesn’t have “System Administrator” security role.
Since we will make async API request to achieve this, returning appropriate boolean value as shown in below code will not affect visibility of the button:
DXC.ShowHideDeleteDocumentButton = function (selectedControl) { //we wanted to hide Delete button on Document subgrid for a particular entity for which we passed SelectedControl CRM Parameter in Ribbon Workbench to check the relationship name if (selectedControl.getRelationship().name === "tri_patientclaimssharing_SharePointDocuments") { var userSettings = Xrm.Utility.getGlobalContext().userSettings; var securityRoles = userSettings.securityRoles; if (securityRoles === null) return false; var globalContext = Xrm.Utility.getGlobalContext(); var req = new XMLHttpRequest(); req.open("GET", globalContext.getClientUrl() + "/api/data/v9.1/roles?$select=roleid&$filter=name eq 'system%20administrator'", true); req.setRequestHeader("OData-MaxVersion", "4.0"); req.setRequestHeader("OData-Version", "4.0"); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.setRequestHeader("Prefer", "odata.include-annotations=\"*\""); req.onreadystatechange = function () { if (this.readyState === 4) { req.onreadystatechange = null; if (this.status === 200) { var results = JSON.parse(this.response); //returns GUID of System Administrator security role in all the Business Units for (var i = 0; i < results.value.length; i++) { var roleid = results.value[i]["roleid"].toLowerCase(); if (securityRoles.includes(roleid) === true) { return true; } } return false; } else { return false; } } }; req.send(); } else { //For all other entities don't hide Delete button on Document subgrid return true; } };
Below is the code for achieving what we want by using promise.
DXC.ShowHideDeleteDocumentButton = function (selectedControl) { //we wanted to hide Delete button on Document subgrid for a particular entity for which we passed SelectedControl CRM Parameter in Ribbon Workbench to check the relationship name if (selectedControl.getRelationship().name === "tri_patientclaimssharing_SharePointDocuments") { var userSettings = Xrm.Utility.getGlobalContext().userSettings; var securityRoles = userSettings.securityRoles; if (securityRoles === null) return false; var globalContext = Xrm.Utility.getGlobalContext(); return new Promise(function (resolve, reject) { var isAdmin = false; var req = new XMLHttpRequest(); req.open("GET", globalContext.getClientUrl() + "/api/data/v9.1/roles?$select=roleid&$filter=name eq 'system%20administrator'", true); req.setRequestHeader("OData-MaxVersion", "4.0"); req.setRequestHeader("OData-Version", "4.0"); req.setRequestHeader("Accept", "application/json"); req.setRequestHeader("Content-Type", "application/json; charset=utf-8"); req.setRequestHeader("Prefer", "odata.include-annotations=\"*\""); req.onreadystatechange = function () { if (this.readyState === 4) { req.onreadystatechange = null; if (this.status === 200) { var results = JSON.parse(this.response); //returns GUID of System Administrator security role in all the Business Units for (var i = 0; i < results.value.length; i++) { var roleid = results.value[i]["roleid"].toLowerCase(); if (securityRoles.includes(roleid) === true) { isAdmin = true; } } resolve(isAdmin); } else { reject(this.statusText); } } }; req.send(); }); } else { //For all other entities don't hide Delete button on Document subgrid return true; } };
NOTE: If the promise does not resolve within 10 seconds, the rule will resolve with a false value.
Hope it helps !!
This was originally posted here.
*This post is locked for comments