Category Archives: Customization

Tips and Tricks for customizing Microsoft CRM 3.0

Dynamics CRM JavaScript: Ensure the current record is Saved before opening a new record

In yesterday’s post, Tracing the Dynamics CRM Form Data save Operation, I discussed identifying data that would be sent to the database when you saved a Dynamics CRM record.

Part of the issue I was facing was related to the form not completing the save operation before I opened a new form record. Since Dynamics CRM 2013 and 2015 user interface rarely opens a new window, the user was getting a warning that there was unsaved data when the page was being switched between the Account and, in this case, the Opportunity record.

So to prevent this from happening, I had to wait for the save to complete then open the new Opportunity record.

Here is the code where I do that:

……

var parameters = { customer_id: customerId, customer_name: customerName, customer_type: customerType, name: Xrm.Page.getAttribute("name").getValue() }; var windowOptions = { openInNewWindow: true }; setTimeout(function () { openNewForm(parameters); }, 2000); } function openNewForm(parameters) { var windowOptions = { openInNewWindow: true }; Xrm.Utility.openEntityForm("opportunity", null, parameters, windowOptions); }

The Details

We are using the JavaScript method setTimeout to wait for 2,000 milliseconds (2 seconds for those of us who are not computers).

At the end of the wait period, we will call a function called openNewForm which will use the Dynamics CRM method Xrm.Utility.openEntityForm, which opens a new Opportunity form.

You may need to adjust the wait period up or down, depending on your environment. The idea is to wait long enough for the save to complete, but not long enough to irritate the user.

Dynamics CRM JavaScript: Working with Tabs and Sections-The right way

Back in March I wrote the following article: Dynamics CRM Developer Tip O’ the Day: Working with Tabs.

Today I was working on some pre-existing customer JavaScript and ran across this:

Xrm.Page.ui.tabs.get(0).sections.get(6).setVisible(false); // Hide section

Don’t ever do that! Bad developer! Bad!

So again, never, ever use the numerical value to reference a Tab or a Section, unless you have no choice. 

We don’t want to use numbers because if you move or add Tabs or Sections, your code will no longer work.

Do this instead:

Xrm.Page.ui.tabs.get("General").sections.get("Details").setVisible(false); // Hide section

As long as your Tabs and Sections are named properly, you should not have an issue.

Manually Repairing a Sitemap. Part 1

As I mentioned a couple of week ago, my upgrade from CRM 2013 to CRM 2015 did not go well. One of the issues is my SiteMap was totally broken and I had to replace it with the “default.”

The only problem was I wiped out the custom entries for my marketing package, Click Dimensions.

No problem, I thought, I’ll just add the solution back.  Except that did not work.  I ran into ghost SiteMap entries from a previously remove solution. This required a call to Microsoft Support to get them corrected.

Once corrected, I was successfully able to import the solution.  Except there were no custom SiteMap entries.

Only only solution in this case is to manually add them, which involves this process:

The Process

1. Create a new solution.

2. Add the SiteMap to the solution.

3. Export the solution as unmanaged.

4. Unzip the solution files.

5. Take the solution file from the package you are attempting to import and unzip it as well.

6. Open the customization.xml file from step 4 in an editor like Visual Studio or Notepad++.

7. Open the customization.xml file from step 5 in an editor like Visual Studio or Notepad++.

8. Copy the information from the step 7 SiteMap and paste it into the proper location within the step 6 SiteMap.

9. You will need to remove some XML attributes that are specific to the Solution Import process. Here is an example:

<Group Id="Extensions" ResourceId="Group_Extensions" ordinalvalue="5" solutionaction="Added" />

You need to remove the any reference to ordianvalue and solutionaction.

10. Save the step 6 customization.xml file.

11. Re-Zip the files from step 4.

12. Import the solution back into CRM.

13. Refresh your browser and see if the SiteMap changes worked.

Things to Know

I did not get into great detail about the SiteMap itself because you really have to understand how it is organized and all of the components that are involved. If you do not understand these things, you can damage the SiteMap and render your CRM system inaccessible.

Before you start anything like this, please know and understand what you are doing.  See the references below.

If all else fails, open a case with Microsoft.

References

Edit the site map

SiteMap XML reference

CRM JavaScript Conversion Strategies Summary

Over on my main company site, CRM Accelerators, I have concluded a series on strategies related to converting your JavaScript from Dynamics CRM 4.0 to 2011+.

Strategies

Here is the summary:

Webinar Recording

I also conducted a free webinar for MSDynamicsWorld recently and you may view that recording here:

http://msdynamicsworld.com/story/microsoft-dynamics-crm-javascript-upgrade-strategies-recorded-webcast

Other Resources

Finally, I have a page dedicated to the topic of upgrading from Dynamics CRM 4.0 to 2011+:

http://www.crmaccelerators.net/dynamics-crm-4-0-2011-upgrade-tips/

It contains links to all of my articles and tools, plus links to articles written by others that I thought would be beneficial.

Setting a Section Label based on a Field Value

I was adding some “fancy” to a Contact form today that I thought I would share with you:

 

The Concept

On the Contact form, I have added the two sets of addresses that are built into Contact and am calling them Primary Address and Secondary Address.  I thought it would enhance the user experience to change the label when a user specifies the actual type of address.

The result is something like this:

image

 

The Implementation

Follow these steps to implement this solution:

Step 1

1. Create two sections on the form to hold the fields, one for Address1 fields, the second for Address2 fields. Each should be configured like this:

image

2. Add the address fields to the form, to their respective sections.

 

Step 2

Add the JavaScript above to the web resource for Contact.  If you already have an onLoad method, just add those two lines of code to your method.

 

Step 2:

Add events to each of the Address Type fields:

SNAGHTMLf2ab9f7

Notice that the Pass execution context as first parameter is checked. This is vitally important and the process will not work without it..

Save and publish the form.

 

Step 3:

Testing using the following protocol:

1. Open a new Contact.

2. Change the value of the Primary Address type.

3. You should see the Primary Address section label change.

4. Repeat steps 1-3 for the Secondary address.

5. Save and close the record.

6. Reopen the record.

7. Verify that the section headers change.

 

Code Review

Let’s take a deeper dive into the code.  I could have hard-coded the section values into our JavaScript but I thought that it would be better to make a fairly generic version of our code.

Take a look at the beginning of function.

function addressType_onChange(executionContextObj) {
    var field = executionContextObj.getEventSource();

This code gets a handle to the attribute which fired the change event.

Since we are working with an OptionSet, we need to get the label for the currently selected value:

var addressType = field.getText();

Next, a check to make sure we actually have a value:

if (addressType != null && addressType != "") {

And finally, the tricky part:

field.controls.get(0).getParent().setLabel(addressType + " Address")

 

field is a handle to the attribute, but we need to get to the parent Section where the attribute resides. Unfortunately, the getParent() method is only associate with a form control. 

.controls.get ( 0 ).getParent() will get the parent of the first control associated with the attribute, with the parent being the Section itself

Note: This is making an assumption that the field is not on the form more than once.

Finally, setLabel() is actually going to reset the label for the Section using the value from the Address Type OptionSet and the word Address.

 

Conclusion

You can use the exact same technique with other field types, but you will need to modify the .getText method to .getValue and change the validity check statement to match the data type being retrieved.

Other than that, this is a pretty simple piece of code.

CRM SDK Nugget: Metadata Browser

Way back when, like in version 3.0 and 4.0, Dynamics CRM had a hidden page that would display a list of entities and attributes in a concise list.

That went away in version 2011 but the good folks on the CRM SDK team (Jim specifically), created a managed solution that was included in the SDK.

The main purpose of the tool is to show you information about CRM entities that does not show up on the normal CRM user interface through the dialogs associated with solutions.  This information is available, but only available via programmatic access.

My utility SnapShot! for Dynamics CRM uses exactly the same techniques to produce reports showing information not normally seen through the CRM UI.

 

Installation

After you have downloaded and installed the SDK, you can find the Metadata Browser here:

sdk\Tools\MetadataBrowser

Install the Metadata Browser as you would any other managed solution. When finished, open the solution and go to the Configuration page, where you can launch the different Metadata Browser components.

 

Metadata Browser

The first tool is the main Metadata Browser itself, which you activate by clicking the Open Metadata Browser button:

image

The interface looks like this:

image

As you click on an entity on the left-hand side, it’s properties will be displayed on the right.

At this point you can either view or edit the entity and its details.

 

Entity Metadata Browser

The second function will display a dialog that will allow you to edit an entity. This is the same dialog that is shown when you click the Edit Entity button on the Metadata Browser.

Here is what that interface looks like:

image

As you can see, you can edit or view any of the properties of the entity.

 

In conclusion, this is a simple yet powerful tool and one that is often overlooked but one which is great to have in your toolbox, should you need it.

Updated: How much space are my Attachments using? (OnPremise)

I was digging through a customer’s CRM database today to determine where all of the space had gone and thought I would share a couple of SQL scripts I created to help.

Note: You’ll need Administrator access to SQL to run these scripts.

This script will give you a summary of all Annotations, broken down by MimeType, which is the format of the file as it was explained to Dynamics CRM when added to the database.

 

SELECT
    MimeType,
    COUNT(Mimetype) AS Count,
    SUM(CAST(FileSize / (1024)AS DECIMAL(12,2))) AS 'Size (KB)',
    CAST(SUM(CAST(FileSize AS DECIMAL)) / (1024*1024) AS DECIMAL(12,2)) 
         AS 'Size (MB)'
FROM
    Annotation
WHERE
    MimeType IS NOT NULL
GROUP BY
    MimeType

Here are the results:

image

As you can see, most of the attachments are PDF files.

If you would like to see where all of your attachments reside, try this script:

select 
    distinct(Annotation.objecttypecode),
    MetadataSchema.Entity.Name,
    COUNT(Annotation.objecttypecode) as Count
from
    Annotation
    join MetadataSchema.Entity on 
        MetadataSchema.Entity.ObjectTypeCode = annotation.ObjectTypeCode 
group by
    Annotation.objecttypecode,
    MetadataSchema.Entity.Name
order by
    Annotation.objecttypecode

 

Here are the results:

image

As you can see, most of my attachments are associated with Fax activities. This is expected, in this particular case, because most of the customer’s inbound communications is still via fax.

To locate attachments that are e-mail related, use this script:

SELECT
    MimeType,
    COUNT(Mimetype) AS Count,
    SUM(CAST(FileSize / (1024)AS DECIMAL(12,2))) AS 'Size (KB)',
    CAST(SUM(CAST(FileSize AS DECIMAL)) / (1024*1024) AS DECIMAL(12,2)) AS 'Size (MB)'
FROM
    ActivityAttachment
WHERE
    MimeType IS NOT NULL
GROUP BY
    MimeType
    

Which produces the following results:

image

To see where these attachments reside, run this script:

select 
    distinct(ActivityAttachment.objecttypecode),
    MetadataSchema.Entity.Name,
    COUNT(ActivityAttachment.objecttypecode) as Count
from
    ActivityAttachment
    join MetadataSchema.Entity on 
        MetadataSchema.Entity.ObjectTypeCode = ActivityAttachment.ObjectTypeCode 
group by
    ActivityAttachment.objecttypecode,
    MetadataSchema.Entity.Name
order by
    ActivityAttachment.objecttypecode

 

Which produces these results:

image

Upcoming Training: JavaScript Development in Dynamics CRM

I am very excited to announce that my workshop on Dynamics CRM JavaScript Development is now ready. The goal of the class is for me to give you a very thorough introduction to using JavaScript within Dynamics CRM.

After a good deal of consideration, I have decided to take the normal two days of instruction and split it into four days of four hours each.  This should allow students time to better absorb the material as well as get their normal work accomplished.

Here are the specifics:

When:
Session 1
: Monday, January 27th through Thursday, January 30th. 7:00am-11:00am each day.

Register for Session 1

 

Session 2: Monday, January 27th through Thursday, January 30th. 1:00pm-5:00pm each day.

Register for Session 2

 

Where:
Online using GoTo Meeting.

What:
This is a hands-on workshop with each student provided their own virtual development environment for the duration of the class.

Cost:
$895 per person (multi-student discounts available)

 

Note: Due to the interactive nature of this workshop, it will be limited to 10 students.

Student Prerequisite Knowledge:

  • Each student must have working knowledge of Dynamics CRM 2011.
  • Knowledge of JavaScript is also required.

Note: For those students that have not worked with JavaScript previously, a short introduction webinar will be conducted on Friday, January 24th. Students attending this webinar will be expected to have completed the accompanying self-study materials before Monday's class begins. Everyone must be ready to run on Monday for the main class.

 

Agenda:
Each classroom day will be four hours in length, with the virtual environments available for student use all day, until midnight of January 30th.

And thanks to our virtual development environments, the majority of our time will be spent actually developing JavaScript solutions for Dynamics CRM.

Think labs. Lots and lots of labs. And homework. There will be homework.

We'll cover the following topics:

  • Creating a development environment
    • Setup
    • Source control
    • Working in teams
    • Working with Visual Studio
  • Working with Web Resources
  • Working with Solutions
  • Working with Forms
    • JavaScript libraries
    • Form events
    • Form Event Handler Execution Context Reference
  • Working with the Xrm.Page Object Model
    • Working with Collections
    • Data operations
    • Tabs and Sections
    • Working with Controls
    • Working with iFrames
    • Working with Navigation Items
  • Ribbon button and JavaScript connection
  • Opening Dynamics CRM Forms and Web Resources via JavaScript
  • Using the XrmSrcToolkit to CRM-related data operations

We will be using about 75 of the methods found in the Xrm.Page object model so you should leave class with a fairly good understanding of where things are and how to access them.

If we have time, we will also cover some of the freely available JavaScript components that can be used to aid in your development efforts and to increase your user's productivity.

Students will also receive a draft copy of my upcoming book on Dynamics CRM JavaScript development along with sample code and utility web resources that should help you kick start your CRM JavaScript development efforts.

 

Please email me if you have any questions: mitch at crmaccelerators dot net

ALM for Microsoft Dynamics CRM 2011: CRM Solution Lifecycle Management

As Microsoft Dynamics CRM continues pushing towards the enterprise space, it becomes increasingly important to support the requirements of the enterprise—not only through the product but also in terms of functionality, scale, resilience, and security.

From an implementation perspective, enterprises expect to be able to have structured, repeatable processes that are predictable and well documented to manage their application lifecycle.

To date, a number of approaches have been articulated through various channels and from a variety of sources, but a definitive and full lifecycle approach has not been concisely communicated by Microsoft.

Many customers, partners, and consultants within MCS are reaching out for best practice advice and guidance, and it is Microsoft’s responsibility to deliver on this expectation. This document focuses on providing a coherent end-to-end approach to enterprise development for Dynamics CRM.

http://www.microsoft.com/en-us/download/details.aspx?id=39044