Friday, August 15, 2014

Disabling the Lookup View Picker in CRM 2013


One of the shortcomings of lookup controls in CRM 2011 and 2013 is that you can’t disable the View Picker once you enter a new custom view. Although you can set it as default and put it first on the list, users can still select records related to other views.



When 2011 was introduces it seemed that this missing SDK ability was no more than a glitch.
Unfortunately it’s still an issue in 2013 and yet again we are required to find undocumented features to enforce this type of business rule.

Luckily both 2011 and 2013 has this feature built into the product. We just needed to find a way to activate it without hindering existing CRM functionality.

In order to handle all the lookup internals, supported and unsupported, I’ve created an XrmLookupField wrapper. The wrapper enables me to manipulate the control with ease and I suggest you do the same in your code.

There is one thing you need to remember about this feature. Once you disable the View Picker you can’t add custom views to it. You must enable the View Picker before you add new customs views and disable it again if you so require.

If you take a closer look at the AddLockedView method in the code sample you’ll notice that this is exactly what I’m doing before adding a new custom view.
i.e. EnableViewPicker(); > AddCustomView() > DisableViewPicker()

This is how we did it in 2011
Note: This XrmLookupField example only includes methods that are relevant to this post.

//SDK wrapper for lookup field 2011
function XrmLookupField(sId) {
    var xlf = this;
    //control instance
    xlf.Ctl = Xrm.Page.getContorl(sId);
    //dom instance
    xlf.Dom = document.getElementById(sId);
    //jquery instance
    xlf.$ = $(xlf.Dom);

    //use that to disable the view picker
    xlf.DisableViewPicker = function () { 
        xlf.SetParameter("disableViewPicker", "1"); 
    }
    //use that to enable the view picker
    xlf.EnableViewPicker = function () { 
        xlf.SetParameter("disableViewPicker", "0");  
    }
    //set undocumented attributes
    xlf.SetParameter = function (sName, vValue) { 
        xlf.$.attr(sName, vValue);  
    }   
    //add locked view
    xlf.AddLockedView = function (sViewId, sEntityName, sViewDisplayName, sFilterXml, sFilterLayout) {
        //first enable the view picker
        xlf.EnableViewPicker();
        //add the custom view (last parameter set the view as default)
        xlf.Ctl.addCustomView(sViewId, sEntityName, sViewDisplayName, sFilterXml, sFilterLayout, true);
        //lock the view picker
        xlf.DisableViewPicker();
    }
    //create new guid
    xlf.NewGuid = function () {
        var d = new Date().getTime();
        var guid = '{xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx}'.replace(/[xy]/g, function (c) {
            var r = (d + Math.random() * 16) % 16 | 0;
            d = Math.floor(d / 16);
            return (c == 'x' ? r : (r & 0x7 | 0x8)).toString(16);
        });
        return guid;
    }
}


And here is a usage example. Note that I’m using the dynamic FetchXml builder to construct my Layouts and FetchXml queries.
You can read more about it here or use regular xml in your code.

//entity onload js
var myLookup1;

//call this function from OnLoad handler
function OnCrmPageLoad() {
    myLookup1 = new XrmLookupField("new_lookup1");
    myLookup1.AddLockedView(
        //sViewId
        myLookup1.NewGuid() ,
        //sEntityName
        "account",
        //sViewDisplayName
        "My Locked Custom View",
        //sFilterXml
        fetch()
            .entity("account")
                .attribute("name")
                    .filter()
                        .condition("name" , fetch.op.Eqaul, "My Company")
        .toString(),
        //sFilterLayout
        layout(1, "name", "accountid")
            .column("name", 200)
        .toString()
    );
}


CRM 2013 introduced some interesting changes. Controls now have a double layout state, one for printing or a read-only state and another for inline editing.
This also means that the built-in feature that controls the View Picker changed.
Luckily, now that we have our XrmLookupField wrapper, we only need to make slight modification in order to make this feature work again and apply it in all our forms.

Following are the required XrmLookupFIeld additions for 2013
I added a comment above each addition to make it noticeable



//SDK wrapper for lookup field 2013
function XrmLookupField(sId) {
    var xlf = this;
    //control instance
    xlf.Ctl = Xrm.Page.getContorl(sId);
    //dom instance
    xlf.Dom = document.getElementById(sId);
    //jquery instance
    xlf.$ = $(xlf.Dom);
 
    /* 2013 addition --- Inline Control instance --- */
    xlf.$i = $("#" + sId + "_i");

    //use that to disable the view picker
    xlf.DisableViewPicker = function () { 
        /* 2013 addition --- The attribute capitalization changed */
        xlf.SetParameter("disableviewpicker", "1"); 
    }
    //use that to enable the view picker
    xlf.EnableViewPicker = function () { 
        /* 2013 addition --- The attribute capitalization changed */
        xlf.SetParameter("disableviewpicker", "0");  
    }
    
    //set undocumented attributes
        xlf.SetParameter = function (sName, vValue) { 
        xlf.$.attr(sName, vValue);  

        /* 2013 addition --- Also change the inline contorl value */
        xlf.$i.attr(sName, vValue);
    }   
    
    //add locked view
    xlf.AddLockedView = function (sViewId, sEntityName, sViewDisplayName, sFilterXml, sFilterLayout) {
        //first enable the view picker
        xlf.EnableViewPicker();
        //add the custom view (last parameter set the view as default)
        xlf.Ctl.addCustomView(sViewId, sEntityName, sViewDisplayName, sFilterXml, sFilterLayout, true);
        //lock the view picker
        xlf.DisableViewPicker();
    }
    //create new guid
    xlf.NewGuid = function () {
        var d = new Date().getTime();
        var guid = '{xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx}'.replace(/[xy]/g, function (c) {
            var r = (d + Math.random() * 16) % 16 | 0;
            d = Math.floor(d / 16);
            return (c == 'x' ? r : (r & 0x7 | 0x8)).toString(16);
        });
        return guid;
    }
}

And finally , the usage is exactly the same as above saving us a tone of work 
Fill free to comment

Cheers,
Adi

1 comment:

  1. Hi Adi,

    do you have a tip for me, why to disable the viewPicker is not working under crm 2016 online Wave 1?

    Here my script:

    function disableViewPicker () {

    var lookup = Xrm.Page.getControl("lookup_WorkTags");

    if (lookup) {
    var id = "{E57F5DE2-7764-E611-80DD-C4346BAC0E68}"; // Tag lookup view for work
    var defaultView = lookup.getDefaultView();

    if (defaultView != id) { lookup.setDefaultView(id); }

    lookup.SetParameter("disableViewPicker", "1"); //setDisabled(true);
    }

    setTimeout( function () { disableViewPicker(); } , 1000);

    }

    Frank

    ReplyDelete