Dynamically Populating Ribbon Flyout Menu in Unified Interface

My previous post Dynamically Populating Ribbon Flyout Menu describes the way to add flyout menu buttons dynamically, but that was limited to web client and was not working in unified Interface.

As per my R&D and support ticket with Microsoft, we are still not able to add dynamic Flyout menu buttons directly in Unified Interface (UCI).

The issue is due to the dynamic buttons don't detect the command that we were adding through our JS code, so we need to attach that command to a hidden button so that internally the command is visible.

Following are the two steps we need to achieve the dynamic flyout in both Web client and unified interface. These steps are actually a continuation of my previous post.

Step#1: Adding a button, where you need to call the command that we have used for dynamic buttons.
Add a flyout button and make it hidden.


Add a menu section and then add a button, and call the command here.

Step#2: We need to update the JS code, i.e to append "lead|NoRelationship|Form|" (this is for lead entity form ribbon) at the start of the actual command for UCI.
function populateEnrollmentFlyout(commandProperties) { 
    var programsRibbonXml = "";
    var programs = retrieveMultiple('msd_programs', "?$select=msd_programid,msd_name");
 
    var command="msd.lead.Command.ProgramClicked";

    //This code is used to build the command string for UCI
    if(commandProperties.SourceControlId!=null)
    {
        var source=commandProperties.SourceControlId.split('|');
        if(source.length>3)
        {
             //command="lead|NoRelationship|Form|msd.lead.Command.ProgramClicked"
             command=source[0]+"|"+source[1]+"|"+source[2]+"|"+command;
        }
    }
    programsRibbonXml +="<MenuSection Id='msd.Lead.Programs.MenuSection' Sequence='10'><Controls Id='msd.Lead.Programs.Control'>"
    if (programs != null) {      
        for (var i = 0; i < programs.length; i++) {           
                var Name = programs[i].msd_name;
                var Value = programs[i].msd_programid;                
                programsRibbonXml+="<Button Id='" + Value + "' Command='" + command + "'  Sequence='"+((i+1)*10)+"' LabelText='" +Name +"' />" 
        }
    }
    programsRibbonXml +="</Controls></MenuSection>";
    commandProperties["PopulationXML"] = '<Menu Id="msd.Lead.Programs.Menu">' + programsRibbonXml + "</Menu>";
}
function programClicked(commandProperties) {
 alert ("program with id "+commandProperties.SourceControlId +" selected.");
}

Finally, the dynamic menu buttons will be shown in both Web client & Unified Interface.


















Hope it will help!

Retrieve Multiple through fetch XML using Web API


Following is a detail sample code to retrieve multiple records using fetchXml query using Web API in Dynamics CRM.
/*
entityPlurarName: entityPlurarName is the plural entity logical name of entity e.g for account it is accounts. for opportunity it is opportunities
fetchXml: fetchXml
return:- entity collections object      
*/
 function executeFetchXml(entityPlurarName, fetchXml) {
    var data = null;
    var req = new XMLHttpRequest();
    req.open('GET', Xrm.Page.context.getClientUrl() + "/api/data/v8.1/" + entityPlurarName + "?fetchXml=" + encodeURIComponent(fetchXml), false);
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("Content-type", "application/json; charset=utf-8");
    req.setRequestHeader("OData-MaxVersion", "4.0");
    req.setRequestHeader("OData-Version", "4.0");
    req.send();
    if (req.readyState === 4) {
        if (req.status === 200) {
            data = JSON.parse(req.response);
        }
        else {
            var error = JSON.parse(req.response).error;
            console.log(error.message);
        }
    }
    return data;
}
You can call the executeFetchXml method as:
 var fetchXml = " <fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>" +
                " <entity name='account'>" +
                " <attribute name='name' />" +
                " <attribute name='primarycontactid' />" +
                " <attribute name='telephone1' />" +
                " <attribute name='accountid' />" +
                " <order attribute='name' descending='false' />" +
                " <filter type='and'>" +
                " <condition attribute='modifiedon' operator='last-seven-days' />" +
                " </filter>" +
                " </entity>" +
                " </fetch>";
    var data = executeFetchXml('accounts', fetchXml);
    if (data !== null && data.value.length > 0) {
        console.log("Account Name :" + data.value[0].name);
        //you code here
    }


Retrieve Multiple using Web API

Following is a detail sample code to retrieve a record using Web API in Dynamics CRM.
/*
entityName: entityName is the plural entity logical name of entity e.g for account it is accounts. for opportunity it is opportunities
query: the odata query
return:-Entity records       
*/
function retrieveMultiple(entityName , query) {
    var data = null;
    var req = new XMLHttpRequest();
    req.open('GET', Xrm.Page.context.getClientUrl() + "/api/data/v8.2/" + entityPlurarName + query, false);
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("Content-type", "application/json; charset=utf-8");
    req.setRequestHeader("OData-MaxVersion", "4.0");
    req.setRequestHeader("OData-Version", "4.0");
    req.send();
    if (req.readyState == 4) {
        if (req.status == 200) {
            data = JSON.parse(req.response);
        }
        else {
            var error = JSON.parse(req.response).error;
            console.log(error.message);
        }
    }
    return data
}
You can call the above retrieveMultiple method as:
var data = retrieveMultiple('roles', "?$select=roleid&$filter=name eq 'Project Manager'");
    if (data != null && data.value.length > 0)
    {
        var PMRoleID= data.value[0].roleid;
    }

Dynamically Populating Ribbon Flyout Menu

I was having a requirement to generate a dynamic ribbon menu under a button i.e. Flyout button menu sections, Here I want to share the steps for achieving this dynamic menu section. I have used Ribbon workbench and some JS scripts.

We need to achieve the highlighted menu dynamically.



Here in workbench, we need to add a flyout button
In the command action, call JS function "populateEnrollmentFlyout" that is responsible for adding the menu sections definition in XML. 

Add another command "programClicked"
 that will be triggered when the user clicks on the menu section button.

Below are the two JS functions used in the above commands.

 function populateEnrollmentFlyout(commandProperties) {
    var programsRibbonXml = "";
    var command="msd.lead.Command.ProgramClicked";
 
    var programs = retrieveMultiple('msd_programs', "?$select=msd_programid,msd_name"); 
    programsRibbonXml +="<MenuSection Id='msd.Lead.Programs.MenuSection' Sequence='10'><Controls Id='msd.Lead.Programs.Control'>"
    if (programs != null) {      
        for (var i = 0; i < programs.length; i++) {           
                var Name = programs[i].msd_name;
                var Value = programs[i].msd_programid;                
                programsRibbonXml+="<Button Id='" + Value + "' Command='" + command + "'  Sequence='"+((i+1)*10)+"' LabelText='" +Name +"' />" 
        }
    }
    programsRibbonXml +="</Controls></MenuSection>";
    commandProperties["PopulationXML"] = '<Menu Id="msd.Lead.Programs.Menu">' + programsRibbonXml + "</Menu>";
}

function programClicked(commandProperties) {
    alert ("program with id "+commandProperties.SourceControlId +" selected.");
}



Hope it will help!

You can find my new blog for adding flyout menu buttons in UCI: 

Dynamically Populating Ribbon Flyout Menu in Unified Interface

Get Status Reasons (statuscode) for a specific status (Statecode) from metaData

Following is sample code for getting statuses for an entity from metadata

function getStatusAttributeMetadata(entityName) {  
    var data = null;
    var webApiQuery = Xrm.Page.context.getClientUrl() + "/api/data/v8.2/EntityDefinitions(LogicalName='" + entityName + "')/Attributes/Microsoft.Dynamics.CRM.StatusAttributeMetadata?$expand=OptionSet";

    var req = new XMLHttpRequest();    
    req.open('GET', webApiQuery, false);
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("OData-MaxVersion", "4.0");
    req.setRequestHeader("OData-Version", "4.0");
    req.send();
    if (req.readyState == 4 /* complete */) {
        if (req.status == 200) {
            var results = JSON.parse(req.response);
            data = results.value[0];
        }
        else {
            var error = JSON.parse(req.response).error;
            console.log(error.message);
        }
    }
    return data;
}


You can filter the statuscode by statecode as following

  var statusReasons = getStatusAttributeMetadata("lead");
    if (statusReasons != null) {
        var options = statusReasons.OptionSet.Options;       
        for (var i = 0; i < options.length; i++) {
            if (options[i].State == 2) {
              //do your code here
            }              
        }
    }

Enable Tracing for Dynamics CRM on premises


By Enabling tracing, there created some files that monitor the actions that are performed by Microsoft CRM. These files are helpful when you need to troubleshoot error messages as we can find more information about the issues/errors.
We can enable tracing for dynamics CRM on premises by adding some registry keys on CRM server. However, make sure to follow following steps carefully, as there might occur serious problems when you modify registry incorrectly.
1.     Go to CRM server
Open registry (runà regedit)
2.     HKEY_LOCAL_MACHINEàSoftwareà MicrosoftàMSCRMàadd new keys
a.     Name: TraceEnabled
Type: DWORD
Value: 1
b.     Name: TraceDirectory
Type: String
Value: C:\CRMTrace
c.     Name: TraceRefresh
Type: DWORD
Value: 99
3.     Create the folder "CRMTrace" in C directory
4.     Reset IIS (Run CMD as administrator >> execute this “iisreset” command )

After doing above steps, perform the action with CRM where you were facing issues, then go to folder (Trace directory), there you will find some tracing files will be created containing detail description.

After troubleshooting your issues, we should disable (provide value “0” to TraceEnabled registry key) the tracing and resetting the IIS. As constant tracing running will have a performance impact on your system and consume disk space.

Enjoy Bug fixing!!!

Auto Complete in Dynamics CRM

Following is sample JavaScript code to demonstrate the auto completion feature. This sample configures the auto-complete feature for a custom single line of text that auto complete years.



Call following function on form load event, this will auto populate the last 60 years in the field when do keypress on this field.

function year_AutoComplete() {
    var keyPressFcn = function (ext) {       
        try {           
            resultSet = {
                results: new Array()                
            };
            var dt = new Date();           
            for (i = 0; i < 50; i++) {               
                    resultSet.results.push({
                        id: i,
                        fields: [dt.getFullYear() - i]
                    });                           
            }         

            if (resultSet.results.length > 0) {
                ext.getEventSource().showAutoComplete(resultSet);
            } else {
                ext.getEventSource().hideAutoComplete();
            }
        } catch (e) {          
            console.log(e);
        }
    };
   
    Xrm.Page.getControl("new_year").addOnKeyPress(keyPressFcn);
}