locked
CRM 2011: Deactivating custom entity record using java script and custom ribbon button RRS feed

  • Question

  • Hi all,

    Trying to create ribbon button for a custom entity to deactivate records

    So I have added the below code to the "<entity name>_ribbon.js" file to be called when clicking the ribbon button

    function Activate(value)
    {
        var r = confirm("This operation will set the selected Money Box as Active.");
        if (r == true)
        {
            //            disablefields();
    
            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            var selectedRecordId = value;
    
            if (typeof (SDK) == "undefined")
            { SDK = { __namespace: true }; }
            //This will establish a more unique namespace for functions in this library. This will reduce the 
            // potential for functions to be overwritten due to a duplicate name when the library is loaded.
            SDK.SAMPLES = {
                _getServerUrl: function ()
                {
                    ///<summary>
                    /// Returns the URL for the SOAP endpoint using the context information available in the form
                    /// or HTML Web resource.
                    ///</summary>
                    var OrgServicePath = "/XRMServices/2011/Organization.svc/web";
                    var serverUrl = "";
                    if (typeof GetGlobalContext == "function")
                    {
                        var context = GetGlobalContext();
                        serverUrl = context.getServerUrl();
                    }
                    else
                    {
                        if (typeof Xrm.Page.context == "object")
                        {
                            serverUrl = Xrm.Page.context.getServerUrl();
                        }
                        else
                        { throw new Error("Unable to access the server URL"); }
                    }
                    if (serverUrl.match(/\/$/))
                    {
                        serverUrl = serverUrl.substring(0, serverUrl.length - 1);
                    }
                    return serverUrl + OrgServicePath;
                },
                SetStateRequest: function ()
                {
                    var requestMain = ""
                    requestMain += "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
                    requestMain += "  <s:Body>";
                    requestMain += "    <Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
                    requestMain += "      <request i:type=\"b:SetStateRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\" xmlns:b=\"http://schemas.microsoft.com/crm/2011/Contracts\">";
                    requestMain += "        <a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
                    requestMain += "          <a:KeyValuePairOfstringanyType>";
                    requestMain += "            <c:key>EntityMoniker</c:key>";
                    requestMain += "            <c:value i:type=\"a:EntityReference\">";
                    requestMain += "              <a:Id>" + selectedRecordId + "</a:Id>";
                    requestMain += "              <a:LogicalName>intercom_moneybox</a:LogicalName>";
                    requestMain += "              <a:Name i:nil=\"true\" />";
                    requestMain += "            </c:value>";
                    requestMain += "          </a:KeyValuePairOfstringanyType>";
                    requestMain += "          <a:KeyValuePairOfstringanyType>";
                    requestMain += "            <c:key>State</c:key>";
                    requestMain += "            <c:value i:type=\"a:OptionSetValue\">";
                    requestMain += "              <a:Value>1</a:Value>";
                    requestMain += "            </c:value>";
                    requestMain += "          </a:KeyValuePairOfstringanyType>";
                    requestMain += "          <a:KeyValuePairOfstringanyType>";
                    requestMain += "            <c:key>Status</c:key>";
                    requestMain += "            <c:value i:type=\"a:OptionSetValue\">";
                    requestMain += "              <a:Value>2</a:Value>";
                    requestMain += "            </c:value>";
                    requestMain += "          </a:KeyValuePairOfstringanyType>";
                    requestMain += "        </a:Parameters>";
                    requestMain += "        <a:RequestId i:nil=\"true\" />";
                    requestMain += "        <a:RequestName>SetState</a:RequestName>";
                    requestMain += "      </request>";
                    requestMain += "    </Execute>";
                    requestMain += "  </s:Body>";
                    requestMain += "</s:Envelope>";
                    var req = new XMLHttpRequest();
                    req.open("POST", SDK.SAMPLES._getServerUrl(), true)
                    // Responses will return XML. It isn't possible to return JSON.
                    req.setRequestHeader("Accept", "application/xml, text/xml, */*");
                    req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
                    req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
                    var successCallback = null;
                    var errorCallback = null;
                    req.onreadystatechange = function () { SDK.SAMPLES.SetStateResponse(req, successCallback, errorCallback); };
                    req.send(requestMain);
                },
                SetStateResponse: function (req, successCallback, errorCallback)
                {
                    ///<summary>
                    /// Recieves the assign response
                    ///</summary>
                    ///<param name="req" Type="XMLHttpRequest">
                    /// The XMLHttpRequest response
                    ///</param>
                    ///<param name="successCallback" Type="Function">
                    /// The function to perform when an successfult response is returned.
                    /// For this message no data is returned so a success callback is not really necessary.
                    ///</param>
                    ///<param name="errorCallback" Type="Function">
                    /// The function to perform when an error is returned.
                    /// This function accepts a JScript error returned by the _getError function
                    ///</param>
                    if (req.readyState == 4)
                    {
                        if (req.status == 200)
                        {
                            if (successCallback != null)
                            { successCallback(); }
                        }
                        else
                        {
                            errorCallback(SDK.SAMPLES._getError(req.responseXML));
                        }
                    }
                },
                _getError: function (faultXml)
                {
                    ///<summary>
                    /// Parses the WCF fault returned in the event of an error.
                    ///</summary>
                    ///<param name="faultXml" Type="XML">
                    /// The responseXML property of the XMLHttpRequest response.
                    ///</param>
                    var errorMessage = "Unknown Error (Unable to parse the fault)";
                    if (typeof faultXml == "object")
                    {
                        try
                        {
                            var bodyNode = faultXml.firstChild.firstChild;
                            //Retrieve the fault node
                            for (var i = 0; i < bodyNode.childNodes.length; i++)
                            {
                                var node = bodyNode.childNodes[i];
                                //NOTE: This comparison does not handle the case where the XML namespace changes
                                if ("s:Fault" == node.nodeName)
                                {
                                    for (var j = 0; j < node.childNodes.length; j++)
                                    {
                                        var faultStringNode = node.childNodes[j];
                                        if ("faultstring" == faultStringNode.nodeName)
                                        {
                                            errorMessage = faultStringNode.text;
                                            break;
                                        }
                                    }
                                    break;
                                }
                            }
                        }
                        catch (e) { };
                    }
                    return new Error(errorMessage);
                },
                __namespace: true
            };
            /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        }
        else
        {
            alert("You pressed Cancel!");
        }
    }

    As it could be clear 'value' contains the selected record ID passed using <CrmParameter>

    The confirmation message is displayed (which means that the function is called) but the record is never deactivated

    Please advise..

    Wednesday, February 8, 2012 4:34 PM

Answers

  • I tried to debug this script with no luck. Anyway I use following method and it worked fine for me:

    SetState = function (entityName, entityId, status, state) {
    	var setStateRequest =
    '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">' +
    	'<s:Body>' +
    		'<Execute xmlns="http://schemas.microsoft.com/xrm/2011/Contracts/Services" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">' +
    			'<request i:type="a:UpdateRequest" xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts">' +
    				'<a:Parameters xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic">' +
    					'<a:KeyValuePairOfstringanyType>' +
    						'<b:key>EntityMoniker</b:key>' +
    						'<b:value i:type="a:EntityReference">' +
    							'<a:Id>' + entityId + '</a:Id>' +
    							'<a:LogicalName>' + entityName + '</a:LogicalName>' +
    							'<a:Name i:nil="true"></a:Name>' +
    						'</b:value>' +
    					'</a:KeyValuePairOfstringanyType>' +
    					'<a:KeyValuePairOfstringanyType>' +
    						'<b:key>State</b:key>' +
    						'<b:value i:type="a:OptionSetValue">' +
    							'<a:Value>' + state + '</a:Value>' +
    						'</b:value>' +
    					'</a:KeyValuePairOfstringanyType>' +
    					'<a:KeyValuePairOfstringanyType>' +
    						'<b:key>Status</b:key>' +
    						'<b:value i:type="a:OptionSetValue">' +
    							'<a:Value>' + status +'</a:Value>' +
    						'</b:value>' +
    					'</a:KeyValuePairOfstringanyType>' +
    				'</a:Parameters>' +
    				'<a:RequestId i:nil="true"></a:RequestId>' +
    				'<a:RequestName>SetState</a:RequestName>' +
    			'</request>' +
    		'</Execute>' +
    	'</s:Body>' +
    '</s:Envelope>';
    	var req = new XMLHttpRequest();
    	req.open("POST", getServerUrl(), false);
    
    	req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
    	req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
    
    	req.send(setEntityStateRequest);
    
    	if (req.status != 200) {
    		getError(req.responseXML);
    	}
    
    }
    
    getServerUrl = function () 
    {
    	var OrgServicePath = "/XRMServices/2011/Organization.svc/web";
    	var serverUrl = "";
    	if (typeof GetGlobalContext == "function") {
    		var context = GetGlobalContext();
    		serverUrl = context.getServerUrl();
    	}
    	else {
    		if (typeof Xrm.Page.context == "object") {
    			serverUrl = Xrm.Page.context.getServerUrl();
    		}
    		else {
    			throw new Error("Impossible to get Server address");
    		}
    	}
    	if (serverUrl.match(/\/$/)) {
    		serverUrl = serverUrl.substring(0, serverUrl.length - 1);
    	}
    
    	serverUrl = serverUrl.replace(/:\/\/([a-z0-9\-._~%]+)(:[0-9]*)?/mg, '://' + location.host);
    	return serverUrl + OrgServicePath;
    }
    getError = function (faultXml) 
    {
    	var errorMessage = "Unknown Error";
    	if (typeof faultXml == "object") {
    		try {
    			var bodyNode = faultXml.firstChild.firstChild;
    
    			for (var i = 0; i < bodyNode.childNodes.length; i++) {
    				var node = bodyNode.childNodes[i];
    
    				if ("s:Fault" == node.nodeName) {
    					for (var j = 0; j < node.childNodes.length; j++) {
    						var faultStringNode = node.childNodes[j];
    						if ("faultstring" == faultStringNode.nodeName) {
    							errorMessage = faultStringNode.text;
    							break;
    						}
    					}
    					break;
    				}
    			}
    		}
    		catch (e) { };
    	}
    
    	alert(errorMessage);
    }
    


    Microsoft CRM Freelancer

    My blog (english)
    Мой блог (русскоязычный)
    Follow Andriy on Twitter

    Thursday, February 9, 2012 9:32 PM
    Moderator

All replies

  • Try using Fiddler (http://fiddler2.com/fiddler2/) to see if your request goes through.

    Blake Scarlavai - http://mscrmdev.blogspot.com/ - Sonoma Partners - http://www.sonomapartners.com/ - Follow @bscarlav

    Wednesday, February 8, 2012 4:42 PM
  • Are you sure the proper statuscode is 2?  By default the active statuscode is 1.
    Wednesday, February 8, 2012 4:47 PM
  • As mentioned above, I'm trying to deactivate the record and yes the required statuscode is 2
    Wednesday, February 8, 2012 6:28 PM
  • Here is code which I'm using to Activate/Deactivate entities (Script#):

       string requestBody = "<s:Envelope xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'>" +
        "<s:Body>" +
         "<Execute xmlns='http://schemas.microsoft.com/xrm/2011/Contracts/Services'>" +
          "<request i:type='b:SetStateRequest' xmlns:a='http://schemas.microsoft.com/xrm/2011/Contracts' xmlns:i='http://www.w3.org/2001/XMLSchema-instance' xmlns:b='http://schemas.microsoft.com/crm/2011/Contracts'>" +
           "<a:Parameters xmlns:c='http://schemas.datacontract.org/2004/07/System.Collections.Generic'>" +
            "<a:KeyValuePairOfstringanyType>" +
             "<c:key>EntityMoniker</c:key>" +
             "<c:value i:type='a:EntityReference'>" + EntityReference.ToXml(entityMoniker) + "</c:value>" +
            "</a:KeyValuePairOfstringanyType>" +
            "<a:KeyValuePairOfstringanyType>" +
             "<c:key>Status</c:key>" +
             "<c:value i:type='a:OptionSetValue'>" +
              "<a:Value>" + status.ToString() + "</a:Value>" +
             "</c:value>" +
            "</a:KeyValuePairOfstringanyType>" +
            "<a:KeyValuePairOfstringanyType>" +
             "<c:key>State</c:key>" +
             "<c:value i:type='a:OptionSetValue'>" +
              "<a:Value>" + state.ToString() + "</a:Value>" +
             "</c:value>" +
            "</a:KeyValuePairOfstringanyType>" +
           "</a:Parameters>" +
           "<a:RequestId i:nil='true'/>" +
           "<a:RequestName>SetState</a:RequestName>" + "" +
           "</request></Execute></s:Body></s:Envelope>";

    ...

     public enum EntityState
     {
      Active = 0,
      InActive = 1
     }

    In order to Activate entity I set state = EntityState.Active, status = -1;

    To Deactivate entity I set state = EntityState.InActive, status = -1;

    Thanks,

    Alexey

    Wednesday, February 8, 2012 6:53 PM
  • Any specific reason why you are not using OOB activate and deactivate Ribbon buttons?

    MaKeer | myencounterwithcrm.wordpress.com | CRM2011 User Settings Utility | CRM2011 Lookup Preview | CRM2011 Lookup Attribute Mapping | CRM2011 TreeView Control (Beta)

    Thursday, February 9, 2012 4:05 AM
  • If you want to use Custom Ribbon button to deactivate records, I would suggest to use CRM's OOB JavaScript functions

    For button that is placed in HomePageGrid following Action can be called in Custom Button Command

       <Actions>
              <JavaScriptFunction FunctionName="Mscrm.GridRibbonActions.deactivate" Library="/_static/_common/scripts/RibbonActions.js">
                <CrmParameter Value="SelectedControl" />
                <CrmParameter Value="SelectedControlSelectedItemReferences" />
                <CrmParameter Value="SelectedEntityTypeCode" />
              </JavaScriptFunction>
            </Actions>

    And for button that is placed in Form following Action can be called in Custom Button Command

     <Actions>
              <JavaScriptFunction FunctionName="changeState" Library="/_static/_forms/form.js">
                <StringParameter Value="deactivate" />
                <CrmParameter Value="PrimaryEntityTypeCode" />
                <StringParameter Value="5" />
              </JavaScriptFunction>
      </Actions>

    HTH.


    MaKeer | myencounterwithcrm.wordpress.com | CRM2011 User Settings Utility | CRM2011 Lookup Preview | CRM2011 Lookup Attribute Mapping | CRM2011 TreeView Control (Beta)

    Thursday, February 9, 2012 4:14 AM
  • Aleksey,

    Is this using C# or javascript !

    Thursday, February 9, 2012 1:32 PM
  • Makarand,

    My customer business logic is as follow: when record is read only then it's activated so I need to reverse functions for activate and deactivate buttons, but when I try to call the deactivate button funcion in the activate button the confirmation message ask if I want to Deactivate the record, so I was tryign to override the whole button behavior

    Best regards..

    Thursday, February 9, 2012 1:36 PM
  • I tried to debug this script with no luck. Anyway I use following method and it worked fine for me:

    SetState = function (entityName, entityId, status, state) {
    	var setStateRequest =
    '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">' +
    	'<s:Body>' +
    		'<Execute xmlns="http://schemas.microsoft.com/xrm/2011/Contracts/Services" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">' +
    			'<request i:type="a:UpdateRequest" xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts">' +
    				'<a:Parameters xmlns:b="http://schemas.datacontract.org/2004/07/System.Collections.Generic">' +
    					'<a:KeyValuePairOfstringanyType>' +
    						'<b:key>EntityMoniker</b:key>' +
    						'<b:value i:type="a:EntityReference">' +
    							'<a:Id>' + entityId + '</a:Id>' +
    							'<a:LogicalName>' + entityName + '</a:LogicalName>' +
    							'<a:Name i:nil="true"></a:Name>' +
    						'</b:value>' +
    					'</a:KeyValuePairOfstringanyType>' +
    					'<a:KeyValuePairOfstringanyType>' +
    						'<b:key>State</b:key>' +
    						'<b:value i:type="a:OptionSetValue">' +
    							'<a:Value>' + state + '</a:Value>' +
    						'</b:value>' +
    					'</a:KeyValuePairOfstringanyType>' +
    					'<a:KeyValuePairOfstringanyType>' +
    						'<b:key>Status</b:key>' +
    						'<b:value i:type="a:OptionSetValue">' +
    							'<a:Value>' + status +'</a:Value>' +
    						'</b:value>' +
    					'</a:KeyValuePairOfstringanyType>' +
    				'</a:Parameters>' +
    				'<a:RequestId i:nil="true"></a:RequestId>' +
    				'<a:RequestName>SetState</a:RequestName>' +
    			'</request>' +
    		'</Execute>' +
    	'</s:Body>' +
    '</s:Envelope>';
    	var req = new XMLHttpRequest();
    	req.open("POST", getServerUrl(), false);
    
    	req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
    	req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
    
    	req.send(setEntityStateRequest);
    
    	if (req.status != 200) {
    		getError(req.responseXML);
    	}
    
    }
    
    getServerUrl = function () 
    {
    	var OrgServicePath = "/XRMServices/2011/Organization.svc/web";
    	var serverUrl = "";
    	if (typeof GetGlobalContext == "function") {
    		var context = GetGlobalContext();
    		serverUrl = context.getServerUrl();
    	}
    	else {
    		if (typeof Xrm.Page.context == "object") {
    			serverUrl = Xrm.Page.context.getServerUrl();
    		}
    		else {
    			throw new Error("Impossible to get Server address");
    		}
    	}
    	if (serverUrl.match(/\/$/)) {
    		serverUrl = serverUrl.substring(0, serverUrl.length - 1);
    	}
    
    	serverUrl = serverUrl.replace(/:\/\/([a-z0-9\-._~%]+)(:[0-9]*)?/mg, '://' + location.host);
    	return serverUrl + OrgServicePath;
    }
    getError = function (faultXml) 
    {
    	var errorMessage = "Unknown Error";
    	if (typeof faultXml == "object") {
    		try {
    			var bodyNode = faultXml.firstChild.firstChild;
    
    			for (var i = 0; i < bodyNode.childNodes.length; i++) {
    				var node = bodyNode.childNodes[i];
    
    				if ("s:Fault" == node.nodeName) {
    					for (var j = 0; j < node.childNodes.length; j++) {
    						var faultStringNode = node.childNodes[j];
    						if ("faultstring" == faultStringNode.nodeName) {
    							errorMessage = faultStringNode.text;
    							break;
    						}
    					}
    					break;
    				}
    			}
    		}
    		catch (e) { };
    	}
    
    	alert(errorMessage);
    }
    


    Microsoft CRM Freelancer

    My blog (english)
    Мой блог (русскоязычный)
    Follow Andriy on Twitter

    Thursday, February 9, 2012 9:32 PM
    Moderator
  • Dear Andriy,

    Thanks alot for your help, it works for me but I have used:

    req.send(setStateRequest);

    instead of:

    req.send(setEntityStateRequest);

    Sunday, February 12, 2012 10:18 AM