- Toll Free: 1-866-SONOMA1
- Email Newsletter
- Blog
- YouTube
- Contact Us
Sonoma Partners
For Every Deactivation There is an Equal and Opposite Reactivation
Posted by Corey O'Brien on June 2, 2011 |Adding Activate Buttons to Microsoft CRM Activity Ribbons
One common customization request we receive for Microsoft CRM is to allow users to reactivate completed activities. Typically this is because a user wants to make a simple update to the record, like correcting a typo.
There are two common ways we can achieve this in Microsoft CRM:
- Executing a manual workflow
- Adding a custom button to the ribbon
A manual workflow is easy to set up, but because the workflow runs asynchronously, it isn’t the best user experience. In this post, I’ll demonstrate the second method - adding a custom ribbon button to reactivate activities.
Part 1: Prepare a Solution
The first step is packaging the activities you are targeting into a custom solution. To do this, open up Microsoft CRM and navigate to the Settings > Customizations > Solutions page. Now, create a new solution. You will be adding a JavaScript library to this solution, so you will want to set up a new publisher to represent your company if you do not already have one. Specify an appropriate Display Name and Version.
Click Save in the solution toolbar and then select the Entities node from the solution components tree on the left. Now click the Add Existing button in the toolbar above the grid, and select each custom activity that you want to add an Activate button to.
Next we’ll add a JavaScript library. Select Web Resources in the solution component tree and then click New from the toolbar above the grid. Enter Scripts/RibbonSample/activateRecord.js for the Name and activateRecord.js for the Display Name. Select Script (JScript) from the Type picklist and then click the Text Editor button.
Paste in the following script:
if (typeof (Sonoma) == "undefined") { Sonoma = {}; }
Sonoma.activateRecord = function (id, logicalName) {
var orgServiceUrl = Xrm.Page.context.getServerUrl() + "/XRMServices/2011/Organization.svc/web";
var request =
'<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="b:SetStateRequest" ' +
' xmlns:a="http://schemas.microsoft.com/xrm/2011/Contracts" ' +
' 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">' +
'<a:Id>' + id + '</a:Id>' +
'<a:LogicalName>' +
logicalName +
'</a:LogicalName>' +
'<a:Name i:nil="true" />' +
'</c:value>' +
'</a:KeyValuePairOfstringanyType>' +
'<a:KeyValuePairOfstringanyType>' +
'<c:key>State</c:key>' +
'<c:value i:type="a:OptionSetValue">' +
'<a:Value>0</a:Value>' +
'</c:value>' +
'</a:KeyValuePairOfstringanyType>' +
'<a:KeyValuePairOfstringanyType>' +
'<c:key>Status</c:key>' +
'<c:value i:type="a:OptionSetValue">' +
'<a:Value>-1</a:Value>' +
'</c:value>' +
'</a:KeyValuePairOfstringanyType>' +
'</a:Parameters>' +
'<a:RequestId i:nil="true" />' +
'<a:RequestName>SetState</a:RequestName>' +
'</request>' +
'</Execute>' +
'</s:Body>' +
'</s:Envelope>';
var req = new XMLHttpRequest();
req.open("POST", orgServiceUrl, true);
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");
req.onreadystatechange = function () {
if (req.readyState === 4) {
location.reload(true);
}
};
req.send(request);
};
This script defines a single method that takes in an entity id and type name. It then makes a call to CRM’s Organization service to activate the record passed in via the parameters. When the service call completes, it reloads the entity form.
Warning: The script is technically unsupported because it accesses the location.reload method on the HTML DOM. However, since there is currenlty not a supported way to refresh the current form, this will be your best bet to provide a good user experience.
Click OK to close the text editor, then Save and Close to create the new web resource.
Export the solution by clicking the Export Solution button at the top of the solution window. This will be an unmanaged solution and we don’t need to include any of the system settings, so leave all of the default options selected as you navigate through the wizard. When prompted, save the solution zip file to a place you will be able to find it on your local computer.
Part 2: Modifying the Solution
Now comes the fun part, we need to open up the exported solution and modify the ribbon definition for each activity we included. Start by extracting all files from the solution zip file into a new subfolder. You should see three files and a WebResources folder extracted.
Open customizations.xml in your favorite XML or text editor. You should see a section similar to the following in each of the entities you included in the solution:
<RibbonDiffXml>
<CustomActions />
<Templates>
<RibbonTemplates Id="Mscrm.Templates"></RibbonTemplates>
</Templates>
<CommandDefinitions />
<RuleDefinitions>
<TabDisplayRules />
<DisplayRules />
<EnableRules />
</RuleDefinitions>
<LocLabels />
</RibbonDiffXml>
Replace the <CommandDefinitions /> element with the highlighted text below:
<RibbonDiffXml>
<CustomActions />
<Templates>
<RibbonTemplates Id="Mscrm.Templates"></RibbonTemplates>
</Templates>
<CommandDefinitions>
<CommandDefinition Id="Mscrm.Form.Activate">
<EnableRules>
<EnableRule Id="Mscrm.CanWritePrimary" />
</EnableRules>
<DisplayRules>
<DisplayRule Id="Mscrm.CanWritePrimary" />
<DisplayRule Id="Mscrm.PrimaryIsInactive" />
<DisplayRule Id="Mscrm.PrimaryEntityHasStatecode" />
</DisplayRules>
<Actions>
<JavaScriptFunction FunctionName="Sonoma.activateRecord"
Library="$webresource:sonoma_Scripts/RibbonSample/activateRecord.js">
<CrmParameter Value="FirstPrimaryItemId" />
<CrmParameter Value="PrimaryEntityTypeName" />
</JavaScriptFunction>
</Actions>
</CommandDefinition>
</CommandDefinitions>
<RuleDefinitions>
<TabDisplayRules />
<DisplayRules />
<EnableRules />
</RuleDefinitions>
<LocLabels />
</RibbonDiffXml>
Note: You will need to change the sonoma_ prefix (as highlighted above in green). This prefix is defined in the publisher you associated with the solution.
Now you might be wondering why we didn’t need to define a button, icons, labels, tooltips, tab location, etc. As it turns out, the activity forms all have this button defined on them natively. They just have a DisplayRule in place to hide them. With this Ribbon change, we’re simply redefining the CommandDefinition to call our custom script and leveraging the existing button definition.
Tip: If you ever need to see an entity’s native ribbon definition, you can check out the Export Ribbon Definitions topic in the CRM SDK.
Part 3: Putting Humpty Dumpty Back Together Again (or Reimporting the Solution)
Now to see these new buttons you’ll need just need to zip up the your exported files (or you can drag the only modified file – customizations.xml – back into your existing solution zip file) and import them back into CRM. To perform the import, navigate back to Settings > Customizations > Solutions within CRM and click the Import button from the toolbar above the grid. Browse to pick your new zip file, and then continue through the rest of the wizard. After the import completes, you can click Publish All Customizations to apply your new change, or if you have other pending changes, you can manually navigate to the activity entities and publish them individually.
Success!
Now if you open a Closed activity you modified, you should see the Activate button in the ribbon:
Comments
Post a Comment
Contact Us for a Quote, or Personalized Demonstrationof Microsoft Dynamics CRM for Your Business.
Contact Us
Previous Post
Back to Blog
Thanks - this is a helpful post. It solves a problem for me. Found it, as luck would have it, while I was googling trying to solve another problem. Trying to figure out how to put an "Insert Article" CRM button into the MS Word Ribbon. We want to reuse the same articles we insert into emails from Outlook by also inserting them into Word documents when appropriate. Don't suppose you have any tips? PS I'm enjoying the Sonoma book
Posted by: Yvonne | Jun 6, 2011 6:09:15 AM