Home

Saturday, September 16, 2017

Show/Hide business process in Dynamics 365


Use getVisible method to retrieve whether the business process control is visible
Xrm.Page.ui.process.getVisible();

Use setVisible method to show or hide the business process flow control.
Xrm.Page.ui.process.setVisible();


// isVisible parameter should be true or false based on your requirement.
function showHideBP(isVisible){   
        Xrm.Page.ui.process.setVisible(isVisible);   
}


Dynamics 365 Javascript Best Practices

Avoid using unsupported methods
As a general rule, any function which is available through Xrm.Page should be considered as supported and rest are unsupported, if you are navigating the HTML DOM structure and using window.getElementById or even manipulating the innerHTML or outerHTML,These methods may work but because they are not supported you can’t expect that they will continue to work in future versions or update rollups of CRM.

Do not use jQuery for form script or commands
Microsoft do not recommend or support using jQuery for any pages within the application. This includes form scripts and ribbon commands

Recognize limitations for content delivery network (CDN) libraries
Content delivery network (CDN) JavaScript libraries provide many advantages for public websites. Because these libraries are hosted on the Internet, you do not need to create web resources that contain the content of the libraries. For Microsoft Dynamics 365 you should consider the following issues before you use a CDN JavaScript library.
  • Users of the Microsoft Dynamics 365 for Microsoft Office Outlook with Offline Access client have the capability to work with no Internet connection while working offline. If you are depending on an Internet connection for your JavaScript libraries, your code will fail.
  • Some organizations will restrict Internet access for employees. Unless they configure the network to allow access to the CDN library sites, your code may fail for those organizations.


Do not access the DOM
The Microsoft Dynamics CRM development team reserves the right to change how pages are composed, including the ID values for elements, so using the Xrm.Page object model protects your code from changes in how pages are implemented.

Use asynchronous data access methods
When you access data by using the Microsoft Dynamics 365 web services, always use an XmlHttpRequest that is configured to execute asynchronously. The reason is that the browser operates on a single thread. If that thread is being used to execute a long-running process synchronously the browser will stop responding.

Keep your libraries as small as possible
JavaScript libraries are stored in web resources and requested by the form each time a form is loaded.  This means that each time the form for a record is opened every JavaScript library tied to that form is downloaded from CRM’s web resource table.  Keep your libraries as simple and as clean as possible. This will increase performance and improve maintainability.

Keep Common utility file to address the common functions
Keep utility file that can be used to write down all the utility functions that would be used across all entities and custom HTML web resources. A classic example would be something like – getUserRoles(). So instead of this you can do something like this.

Create a webresource named myOrg.Utilities.js then you can define the methods in the file like below.

if (typeof (myOrg) == "undefined") {
   myOrg = { __namespace: true };
}
myOrg.Utilities = {
    _getUserInfo: function(){},
   //Other common functions
}

You can then include the webresource wherever you need. To call the method of the file, you would need to use the fully qualified name as
Var isAdmin = myOrg.Utilities._getUserInfo();

Keep separate scripts for forms and ribbon functions for each entity
For example take account entity as an example keep two sets of scripts for easy identifying one for form events and ribbon events.
Account.Form.js – This can be the script for all your form on-load, on-save and on-change events that you register for the form. So if there is any error you are getting during on save, on load and onchange of the form, you can be rest assured that the origin you can trace from this file.
Account.Ribbon.js – This can be very useful. If you place all the custom ribbon button event handler in this file, you no longer need to check the ribbon diff xml to find out which file the ribbon event handler is located in.
for opportunity.form.js

if (typeof (myOrg) == "undefined") {
   myOrg = { __namespace: true };
}
if (typeof (myOrg.Opportunity) == "undefined") {
   myOrg.Opportunity = { __namespace: true };
}
myOrg.Opportunity.Form= {
   _Load: function(){},
   _Save: function(){}
}

Namespace your library names
Associate each of your functions with a JavaScript object to create a kind of namespace to use when you call your functions, as shown in the following example.
//If the MyUniqueName namespace object isn’t defined, create it.
if (typeof (MyUniqueName) == "undefined")
 { MyUniqueName = {}; }

  // Create Namespace container for functions in this library;
  MyUniqueName.MyFunctions = {
   performMyAction: function(){
   // Code to perform your action.
   //Call another function in your library
   this.anotherAction();
  },
  anotherAction: function(){
   // Code in another function
  }
};

Then when you use your function you can specify the full name. The following example shows this.
MyUniqueName.MyFunctions.performMyAction();



Set form notifications in dynamics 365

You can display any number of notifications using “setFormNotification” and they will be displayed until they are removed using clearFormNotification. The height of the notification area is limited so each new message will be added to the top. Users can scroll down to view older messages that have not yet been removed.

Syntax
To clear the notifications on the form.
Xrm.Page.ui.clearFormNotification(uniqueId);
To set  the notifications on the form.
Xrm.Page.ui.setFormNotification(message, level, uniqueId);
To set the notifications on the form for a particular field.
Xrm.Page.getControl(fieldname).setNotification(message, uniqueId);
--------------------------------------------------------------------------------------

To set the notifications on the form.
function setFormNotifications() {
    Xrm.Page.ui.setFormNotification("This is an INFORMATION notification.", "INFO","1");
    Xrm.Page.ui.setFormNotification("This is a WARNING notification. ", "WARNING" , "2");
    Xrm.Page.ui.setFormNotification("This is an ERROR notification. ", "ERROR", "3");
    Xrm.Page.getControl("name").setNotification("Message to display", "101")
}

To clear the notifications from field and form.
function clearFormNotifications() {
    // Cleards notifications from the field "name" with unique identifier 101
    Xrm.Page.getControl("name").clearNotification("101");
    // Clears notifications from the form for unique id 1
    Xrm.Page.ui.clearFormNotification("1");
}

Dynamics 365 JavaScript functions

Get the value from a CRM field
 var varMyValue = Xrm.Page.getAttribute(“ fieldName”).getValue() ;

Set the value of a CRM field
Xrm.Page.getAttribute(“ fieldName”).setValue(‘My New Value’);

Hide/Show a tab/section
Xrm.Page.ui.tabs.get(5).setVisible(false);
Xrm.Page.ui.tabs.get(5).setVisible(true);

Hide/Show field
Xrm.Page.ui.controls.get(fieldName).setVisible(false); Xrm.Page.ui.controls.get(fieldName).setVisible(true);

Call the onchange event of a field
 Xrm.Page.getAttribute(“ fieldName”).fireOnChange();

Get the selected value of picklist
Xrm.Page.getAttribute(“ fieldName”).getSelectedOption().text;

Set the requirement level
Xrm.Page.getAttribute(“ fieldName”).setRequiredLevel(“none”);
Xrm.Page.getAttribute(“ fieldName”).setRequiredLevel(“required”);
Xrm.Page.getAttribute(“ fieldName”).setRequiredLevel(“recommended”);

Update a readonly field
Xrm.Page.getAttribute("fieldName").setSubmitMode("always");

Set the focus to a field
Xrm.Page.getControl(“ fieldName”).setFocus(true);

Disable/Enable field
 Xrm.Page.getControl(fieldName).setDisabled(true); Xrm.Page.getControl(fieldName).setDisabled(false);

Stop an on save event
event.returnValue = false;

Return array of strings of users security role GUIDs
Var arrUserRoles = Xrm.Page.context.getUserRoles();

Get record GUID
var recordId = Xrm.Page.data.entity.getId();
var recordIdWithoutCurlyBraces = Xrm.Page.data.entity.getId().substring(1,37);

Get Organization unique name
var OrganizationUniqueName = Xrm.Page.context.getOrgUniqueName();

Gets current user Guid
var userGUID = Xrm.Page.context.getUserId();

Returns the base URL that was used to access the application.
var clientURL = Xrm.Page.context.getClientUrl();

Returns a string current Microsoft Office Outlook theme chosen by the user.
var currentTheme = Xrm.Page.context.getCurrentTheme();

Returns whether Autosave is enabled for the organization.
var isAutoSaveEnnabled = Xrm.Page.context.getIsAutoSaveEnabled();


Returns the Dynamics 365 Language Pack that is user's preferred language.
var userLCID = Xrm.Page.context.getUserLcid();

Returns the name of the current user
var userLCID = Xrm.Page.context.getUserName();

Returns the version number of the Dynamics 365 server
var currentVersion = Xrm.Page.context.getVersion();

Method to close the form.
Xrm.Page.ui.close();

Method to get the form type of the record.
Xrm.Page.ui.getFormType();

Method to refresh the ribbon.

Xrm.Page.ui.refreshRibbon();

Returns the difference between the local time and Coordinated Universal Time (UTC).
var timeDifference = Xrm.Page.context.getTimeZoneOffsetMinutes();
 
Set Form Notifications in Dynamics 365

Thursday, September 14, 2017

Retrieve an entity using Dynamics 365 Web API


The following example retrieves name and revenue properties for the account entity with the Id

Request
GET [Organization URI]/api/data/v8.2/accounts(00000000-0000-0000-0000-000000000001)?$select=name,revenue HTTP/1.1
Accept: application/json
Content-Type: application/json; charset=utf-8
OData-MaxVersion: 4.0
OData-Version: 4.0

Response
HTTP/1.1 200 OK
Content-Type: application/json; odata.metadata=minimal
OData-Version: 4.0

{
"@odata.context": "[Organization URI]/api/data/v8.2/$metadata#accounts(name,revenue)/$entity",
"@odata.etag": "W/\"502186\"",
"name": "A. Datum Corporation (sample)",
"revenue": 10000,
"accountid": "00000000-0000-0000-0000-000000000001",
"_transactioncurrencyid_value":"b2a6b689-9a39-e611-80d2-00155db44581"
}
------------------------------------------------------------------------------------------------------
function GetRecord() {
   
    var entityName = "accounts", etag;
    var clientURL = Xrm.Page.context.getClientUrl();
    var req = new XMLHttpRequest();

    req.open("GET", encodeURI(clientURL + "/api/data/v8.2/" + entityName + "(00000000-0E99-E711-8127-000000000001)?$select=name,revenue", 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.onreadystatechange = function () {       
        if (this.readyState === 4 /* complete */) {
            req.onreadystatechange = null;
            if (this.status === 200) {
                var result = JSON.parse(this.response);               
            }
            else {
                var error = JSON.parse(this.response).error;
                alert(error.message);
            }
        }
    };

    req.send();
  

}

Apply optimistic concurrency on update Dynamics Web Api

You can use optimistic concurrency to detect whether an entity has been modified since it was last retrieved. If the entity you intend to update or delete has changed on the server since you retrieved it, you may not want to complete the update or delete operation. By applying the pattern shown here you can detect this situation, retrieve the most recent version of the entity, and apply any necessary criteria to re-evaluate whether to try the operation again.

Request
PATCH [Organization URI]/api/data/v8.2/accounts(00000000-0000-0000-0000-000000000001) HTTP/1.1
If-Match: W/"470867"
Accept: application/json
OData-MaxVersion: 4.0
OData-Version: 4.0

{"name":"Updated Account Name"}

Response
HTTP/1.1 412 Precondition Failed
Content-Type: application/json; odata.metadata=minimal
OData-Version: 4.0

{
  "error":{
    "code":"","message":"The version of the existing record doesn't match the RowVersion property provided.",
    "innererror":{
      "message":"The version of the existing record doesn't match the RowVersion property provided.",
      "type":"System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=8.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]",
"stacktrace":"  <stack trace details omitted for brevity>
    }
  }
}

------------------------------------------------------------------------------------------------------
The following update request for an account with accountid of 00000000-0E99-E711-8127-000000000001 fails because the ETag value sent with the If-Match header is different from the current value. If the value had matched means the data which is retrieved is not edited and you have the latest data, a 204 (No Content) status is expected.

function updateLatestData() { // Using optimistic concurrency
  
    var entityName = "accounts";
    var clientURL = Xrm.Page.context.getClientUrl();
    var req = new XMLHttpRequest();
  
    req.open("PATCH", encodeURI(clientURL + "/api/data/v8.2/" + entityName + "(00000000-0E99-E711-8127-000000000001)", true));
    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.setRequestHeader("If-Match", "W/\"470867\"");

    req.onreadystatechange = function () {
        if (this.readyState === 4 /* complete */) {
            req.onreadystatechange = null;
            if (this.status === 204) {
                alert("Record updated");
            }
            else {
                var error = JSON.parse(this.response).error;
                alert(error.message);
            }
        }
    };

    req.send(JSON.stringify(
        {
            name: "Sample Account updated"           
        }));

}

Create related entities in one operation using webapi’s (Deep Insert)



The following request body posted to the Account entity set will create a total of four new entities in the context of creating an account.
·         A contact is created because it is defined as an object property of the single-valued navigation property primarycontactid.
·         An opportunity is created because it is defined as an object within an array that is set to the value of a collection-valued navigation property opportunity_customer_accounts.
·         A task is created because it is defined an object within an array that is set to the value of a collection-valued navigation property Opportunity_Tasks.
-----------------------------------------------------------------------------------------------------
// Request
POST [Organization URI]/api/data/v8.2/accounts HTTP/1.1
Content-Type: application/json; charset=utf-8
OData-MaxVersion: 4.0
OData-Version: 4.0
Accept: application/json
{
 "name": "Sample Account",
 "primarycontactid":
 {
     "firstname": "John",
     "lastname": "Smith"
 },
 "opportunity_customer_accounts":
 [
  {
      "name": "Opportunity associated to Sample Account",
      "Opportunity_Tasks":
      [
       { "subject": "Task associated to opportunity" }
      ]
  }
 ]
}

// Response
HTTP/1.1 204 No Content
OData-Version: 4.0
OData-EntityId: [Organization URI]/api/data/v8.2/accounts(newGuid)
------------------------------------------------------------------------------------------------------
function deepInsert() {

    var entityName = "accounts";
    var clientURL = Xrm.Page.context.getClientUrl();
    var req = new XMLHttpRequest();

    req.open("POST", encodeURI(clientURL + "/api/data/v8.2/" + entityName, true));
    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.onreadystatechange = function () {
        if (this.readyState == 4 /* complete */) {
            req.onreadystatechange = null;
            if (this.status == 204) {
                alert("Records created");
            }
            else {
                var error = JSON.parse(this.response).error;
                alert(error.message);
            }
        }
    };

    req.send(JSON.stringify(
        {
            name: "Sample Account",
            primarycontactid:
            {
                firstname: "John",
                lastname: "Smith"
            },
            opportunity_customer_accounts:
            [
             {
                 name: "Opportunity associated to Sample Account",
                 Opportunity_Tasks:
                 [
                  { subject: "Task associated to opportunity" }
                 ]
             }
            ]
        }));


}

Convert subgrid to Comments