Filter N:N Add Existing Lookup Dynamics CRM 2011 Rollup 12

Paul Nieuwelaar, 04 February 2013

Daniel Cai blogged about how to filter the Add Existing lookup for N:N relationships, however with the introduction of rollup 12, the method for filtering the add existing lookup has changed slightly.

I’ve used the code from Daniels blog post, and made the necessary modifications to make it work with rollup 12, and also previous versions as well in case you don’t know what rollup you’re on.

Note: In this blog post I am using the Ribbon Workbench from develop1 to customize the ribbon XML.

For this example, I have created a N:N between Account and Contact, and will filter the ‘Contact’ view from the Account side to show only contacts with a first name of ‘Paul’.

 Filter N:N Add Existing Lookup Dynamics CRM 2011 Rollup 12

First we need to create the JavaScript web resource containing our functions. The first function below (addExistingFromSubGridCustom) does not need to be modified, as this is just used to inject the custom view into the lookup. The second function (filterAddExistingContact in my case) is the one you will need to modify to meet your own requirements.

I only want to filter the contacts N:N when we click ‘Add Existing’ from the account, so I’ve added another check to ensure we only apply filtering from the Account, and not some other N:N relationships we have with contact.

The full code to add into your web resource is as follows (click here for updated JavaScript for CRM 2013):

//filters an add existing lookup view (N:N)
function addExistingFromSubGridCustom (gridTypeCode, gridControl, fetch, layout, viewName) {
    var viewId = "{1DFB2B35-B07C-44D1-868D-258DEEAB88E2}"; // a dummy view ID 
    var relName, roleOrd;
    if (typeof (gridControl.GetParameter) === "function") { //post rollup 12 
        relName = gridControl.GetParameter("relName");
        roleOrd = gridControl.GetParameter("roleOrd");
    }
    else { //pre rollup 12 
        relName = gridControl.getParameter("relName");
        roleOrd = gridControl.getParameter("roleOrd");
    }

    //creates the custom view object 
    var customView = {
        fetchXml: fetch,
        id: viewId,
        layoutXml: layout,
        name: viewName,
        recordType: gridTypeCode,
        Type: 0
    };

    //pops the lookup window with our view injected 
    var lookupItems = LookupObjects(null, "multi", gridTypeCode, 0, null, "", null, null, null, null, null, null, viewId, [customView]);

    //once the lookup window is closed, we need the parent record ID and ETC before associating selected records 
    if (lookupItems && lookupItems.items.length > 0) {
        var parentId;
        var parentTypeCode;
        if (typeof (GetParentObject) == "function") { //post rollup 12 has its own function to get this 
            var parent = GetParentObject();
            parentId = parent.id;
            parentTypeCode = parent.objectTypeCode;
        }
        else { //pre rollup 12 still needs to use the old way 
            var parent = typeof (crmFormSubmit) == "undefined" ? $get("crmFormSubmit") : crmFormSubmit; //according to daniels blog crmFormSubmit should already be defined, but it's not... 
            if (parent) {
                parentId = parent.crmFormSubmitId.value;
                parentTypeCode = parent.crmFormSubmitObjectType.value;
            }
            else {
                parentId = window.parent.crmFormSubmit.crmFormSubmitId.value;
                parentTypeCode = window.parent.crmFormSubmit.crmFormSubmitObjectType.value;
            }
        }

        //associates the selected records 
        AssociateObjects(parentTypeCode, parentId, gridTypeCode, lookupItems, IsNull(roleOrd) || roleOrd == 2, "", relName);
    }
}

//filters the Contact N:N lookup view from Account to show only Pauls!!
function
filterAddExistingContact (gridTypeCode, gridControl, primaryEntity) {
    if (primaryEntity != "account") {
        Mscrm.GridRibbonActions.addExistingFromSubGridAssociated(gridTypeCode, gridControl); //default button click function 
        return;
    }

    //fetch to retrieve filtered data 
    var fetch = "<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>" +
        "  <entity name='contact'>" +
        "    <attribute name='fullname' />" +
        "    <order attribute='fullname' descending='false' />" +
        "    <filter type='and'>" +
        "      <condition attribute='statecode' operator='eq' value='0' />" +
        "      <condition attribute='firstname' operator='eq' value='Paul' />" +
        "    </filter>" +
        "  </entity>" +
        "</fetch>";

    //columns to display in the custom view (make sure to include these in the fetch query) 
    var layout = "<grid name='resultset' object='1' jump='contactid' select='1' icon='1' preview='1'>" +
        "  <row name='result' id='contactid'>" +
        "    <cell name='fullname' width='300' />" +
        "  </row>" +
        "</grid>";

    addExistingFromSubGridCustom(gridTypeCode, gridControl, fetch, layout, "Filtered Contacts");
}

You can see at the beginning of the ‘filterAddExistingContact’ function I’m checking the parent entity name. If this is not account, we run the default add existing function, and no filtering is applied. We’ve also got our fetchXml and layoutXml which you need to modify to the data you want to retrieve in your filter.

Next we need to edit the contact ribbon. (These steps only apply if you’re using the ribbon workbench, otherwise you need to edit the raw ribbon XML)

Create a temporary solution containing the Application Ribbon, your JavaScript web resource, and the entity you are filtering (in this case Contact).

 Filter N:N Add Existing Lookup Dynamics CRM 2011 Rollup 12

Before you do anything else, you should take an unmanaged backup of this solution in case you need to roll back anything later.

Next open the Ribbon Workbench from the solutions area ribbon. Select the solution you just created. This will export those components, so make sure someone else isn’t customizing them while you do this otherwise theirs will be overridden when the ribbon workbench reimports the solution.

Once the ribbon workbench opens, select the entity we’re customizing (contact), and then from the dropdown menu in the top right corner select SubGrid. There will be two Add Existing buttons, one for N:N and one for 1:N, we want the one on the right (Mscrm.SubGrid.contact.AddExistingAssoc).

 Filter N:N Add Existing Lookup Dynamics CRM 2011 Rollup 12

Right click this button, and Customize Command. Expand Commands in the Solution Elements, and there should be a command called ‘Mscrm.AddExistingRecordFromSubGridAssociated’. Right click this command, and click Edit Actions. Replace the current FunctionName with the new function from your web resource (in my case the second function: filterAddExistingContact), and change the Library to your web resource. In my case I also edited the Parameters to add the PrimaryEntityTypeName.

 Filter N:N Add Existing Lookup Dynamics CRM 2011 Rollup 12

Click on Publish Solution from the top menu, and the solution will be reimported with the changes.

You’re done! When you click the contacts Add Existing button now for N:N relationships the custom function will fire to perform the filtering.

Note: Filtering the Add Existing view like this is unsupported, so there is no guarantee the next major update won’t break this again. But until then, enjoy!