Thursday, April 29, 2010

Querying N:N Relationships

Native N:N Relationships are not considered Entities in CRM 4, therefore the web services will not support using a RetrieveRequest against the N:N table.  However it is possible to query the table using Fetch XML.  Below is a simple Fetch query to retrieve the records in the "systemuserroles" N:N table.

                   

"resultXml" would look something like this:




and now you can parse through the result to grab the data you need.

Wednesday, April 21, 2010

Delete Plugin "Gotcha"

Today I discovered a nice "gotcha" moment when trying to delete a custom entity record.  This is the error I was seeing:



After trying to use a debugger to step into the delete plugin and failing miserably, I finally discovered that the plugin had an image that was not being used.  Once I removed the image and re-registered the plugin, it triggered successfully. 

Further testing revealed that anytime you register a post image with a delete plugin then your plugin will not even trigger and throw the error shown above.  This makes complete sense because the record will not have a post image as it will be deleted.

Thursday, April 15, 2010

ActivityParty Property

The Properties of a DynamicEntity can be confusing at first but are pretty straightforward after you get the hang of it.  However, one property that can be hard to figure out is the ActivityParty.  It is actually an array of DynamicEntity and each DynamicEntity in that array has a Lookup property called "partyid".  Here's a code snippet for retrieving the "to" from an activity DynamicEntity in a plugin.

Note:  This snippet is just finding the first record in the To attribute.

DynamicEntity activity = (DynamicEntity)context.InputParameters.Properties["Target"];
if (activity.Properties.Contains("to"))
{
     DynamicEntity[] to = (DynamicEntity[])activity.Properties["to"];
     if (to.Count() > 0 && to[0].Properties.Contains("partyid"))
     {
          Lookup partyId = (Lookup)to[0].Properties["partyid"];
          // Run logic
     }
}

Saturday, April 10, 2010

Offline IFrames

Not all of your functionality will be possible in CRM Offline mode.  For example you may have some IFrames that require an internet connection.  For these scenarios you would not want to have the browser display an error to the user.  Just hiding the IFrame may not be sufficient enough either as it may confuse your users as to why it disappeared.  A nice solution in this case is to hide the IFrame as well as provide the user with a reason as to why they can't see it.

Here's a function to hide the IFrame and overlay it with div containing a custom message explaining why the user cannot see the IFrame.

function ReplaceOfflineIFrameWithMessage(iFrame, messageText)
{
    if (iFrame)
    {
        iFrame.style.display = "none";

        var messageDiv = document.createElement("div");
        messageDiv.innerText = messageText;
        messageDiv.textAlign = "center";
        messageDiv.style.fontSize = "12px";
        messageDiv.style.color = "red";
        messageDiv.style.border = "1px solid #6699cc";
        messageDiv.style.padding = "20px";

        document.getElementById(iFrame.id + '_d').appendChild(messageDiv);
    }
}

Then you can use the native CRM function IsOnline to see what mode the user is in and then call this function passing in the desired IFrame to hide and the custom message to display.

if (!IsOnline())
    ReplaceOfflineIFrameWithMessage(crmForm.all.IFRAME_TestIframe, "You cannot access this content offline.  Please click 'Go Online' in the Outlook client to access this content.");

Here's an example of how it looks:



Tuesday, April 6, 2010

How to Prevent Closing an Opportunity

If you ever need to execute some logic when a user clicks "Close Opportunity" from the Opportunity form, then a good technique is to wrap CRM's native close javascript function with some custom javascript.

The following javascript should be ran onload of the form.

First we will declare our function that will return a boolean based on whether the user can close the Opportunity or not.

canCloseOpp = function()
{
     var canClose = false;

     // validate if you can close the opp or not

     return canClose; 
} 
 
Then we find the "Close Opportunity" button by id and if it exists 
we will change the action property which will get executed when
the user clicks the button.  We will first call our custom function 
to see if the user can close the opportunity.  If it returns true we 
will call "complete" which is CRM's native function to close an 
opportunity.  If it returns false we will display an alert explaining
why the Opportunity can't be closed. 
 
var btnClose = document.getElementById('_MIcomplete');
if (btnClose)
{
   btnClose.action = 
      "if (canCloseOpp()) { complete(); }" +
      "else { alert('Opportunity can not be closed.'); }";
}

Monday, April 5, 2010

CRM Pop-ups

Working with CRM day in and day out, you will find that sometimes all the pop-ups can get on your nerves.  I offered a solution to someone on the CRM forums on how to change the way IE works to open pop-ups in a new tab (Which was also blogged about by Jim Glass).

Tools -> Options -> In the tab section, click Settings -> Open pop ups in a new tab

Note:  On a form, custom iframes will be noticeably larger in a full tab than in a pop-up, so expect this to look quite different. Most users will likely keep their IE settings default, so keep this in consideration when developing custom iframes.