Thursday, April 24, 2014

Enable or disable custom ribbon button in SharePoint 2013 based on List Item Property [ Field Value ]

You would come to some scenarios in SharePoint where you want to create a ribbon custom action to perform some custom tasks to meet your business needs.

Creating a custom action in SharePoint 2013 is not different than SharePoint 2010, and there are a lot of articles explaining how to create a custom action.

Examples:

  1. SharePoint 2010 Custom Ribbon Button
What about disabling this button when a specific condition is true, The most common example you will find is disabling the ribbon button while more than on list item is selected.
  1. CommandUIHandler Element
  2. Enable or disable custom ribbon button in SharePoint 2010
But what about disabling the custom action based on a field value in the currently selected list item, For example in the Check-in & Check-out buttons in the ribbon is disabled/Enabled based on the Document [Item] Status.

Ok, Then how would you apply the same idea based on your own custom field.

Here comes the magic of using CSOM and ECMA scripts to communicate asynchronously with current list, Getting the current list item fields, then deciding based on the field value if you will Enable/Disable the button.

In the Custom action elements.xml definition you will find a section with the following tag "CommandUIHandler", This tag has "EnabledScript" attribute, Where you can right javascript to return true if enabled, False if the button is disabled.

First you need to check if only one item is selected:


function singleStatusEnable() {
    try{
        var selecteditems = SP.ListOperation.Selection.getSelectedItems();
        var ci = CountDictionary(selecteditems);

        if (ci == 1) {
            return CheckStatus(selecteditems);
        }
        else {
            return false;
        }
    }
    catch (ex) {
        alert('Error occurred: ' + ex.message);
        return false;
    }
}


Then we will have the following plan, We will create a global window variable of array type, To maintain the values of the EnabledScript.

We will use the array index as the ItemID and the value will be either true or false, Why we will do this ?? Simply to not have to check the Item Field value each type the user check/uncheck the item, as each time the item is checked or unchecked the method "RefreshCommandUI()" is called which re-validates all the ribbon buttons to decide wither to enable or disable them according to current selected Item.

If the global window variable is not defined we will initialize it - This will happen only with first selected item - Then we will check if the current item ID already exists in our array if yes we will return the value if not we will check the value asynchronously, after we get the response back from the server we will call the "RefreshCommandUI()" method to re-validate the ribbon buttons


function CheckStatus(selectedItems) {
    //Get Current Context
    var clientContext = SP.ClientContext.get_current();
    //Get Current List
    var currentList = clientContext.get_web().get_lists().getById(SP.ListOperation.Selection.getSelectedList());
    //Get Selected List Item
    var ItemId = selectedItems[0].id;

    //Check if the window global array variable was initialized or not 
    if(window.FolderStatusValue === undefined) {
        window.FolderStatusValue = new Array();
    }
    
    //Check if the current selected ID was previously saved if not Get the Item status and refresh the UI
    if (window.FolderStatusValue[ItemId] === undefined) {
        singleItem = currentList.getItemById(ItemId);
        clientContext.load(singleItem);
        clientContext.executeQueryAsync(Function.createDelegate(this, OnSucceeded), Function.createDelegate(this, OnFailed));
        return false;
    }
    
    //Return the saved value
    return window.FolderStatusValue[ItemId];
}

//When the Async request is completed save the Item value in the array and re-call RefreshCom//mandUI() method
function OnSucceeded() {
    
    var selecteditems = SP.ListOperation.Selection.getSelectedItems();
    var ItemId = selecteditems[0].id;

    var ItemStatus = singleItem.get_item('YOUR-CUSTOM-COLUMN-STATIC-NAME');
    
    
    if (ItemStatus) {
        window.FolderStatusValue[ItemId] = true; //Enable Ribbon button
        RefreshCommandUI();
    }
    else {
        window.FolderStatusValue[ItemId] = false; //Disable Ribbon button
    }
}


function OnFailed(sender, args) {
    alert('Error occurred: ' + args.get_message());
    return false;
}


Here is the full XML definition for the Custom Action  :


<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <CustomAction Id="8d2b47c5-9e1a-4ff2-9a90-071632a0e9db.ShareFolderExternal"
                RegistrationType="ContentType"
                RegistrationId="0x0120001D4A61CCFCF04620B4F487A48EABBD52"
                Location="CommandUI.Ribbon"
                Rights="AddListItems,DeleteListItems,EditListItems">
    <CommandUIExtension>
      <CommandUIDefinitions>
        <CommandUIDefinition
         Location="Ribbon.Documents.Share.Controls._children">
          <Button
           Id="8d2b47c5-9e1a-4ff2-9a90-071632a0e9db.ShareFolderExternal.Button"
           Command="ShareFolderExternally"
           Image16by16="/_layouts/15/images/Share16x16.png"
           Image32by32="/_layouts/15/images/Share32x32.png"
           LabelText="$Resources:DocumentSharing,ShareFolderCA;"
           TemplateAlias="o1"
           Sequence="11" />
        </CommandUIDefinition>
      </CommandUIDefinitions>
      <CommandUIHandlers>
        <CommandUIHandler   Command="ShareFolderExternally"
                            CommandAction="Javascript:
                                            function Operation(dialogResult, returnValue)
                                            {
                                              SP.UI.Notify.addNotification('Successfully Done!');

                                              SP.UI.ModalDialog.RefreshPage(SP.UI.DialogResult.OK);
                                            }
                
                                            var webURL = _spPageContextInfo.webServerRelativeUrl;
                                            var selecteditems = SP.ListOperation.Selection.getSelectedItems();
                                            
                                            var ItemId = selecteditems[0].id;
                                            
                                            var options = {
                                                            url: webURL + '/_layouts/15/Progress.aspx?FolderId=' + ItemId + '&amp;ListId={ListId}',
                                                            title: 'Share Folder Externally',
                                                            allowMaximize: false,
                                                            showClose: true,
                                                            width: 400,
                                                            height: 100,
                                                            dialogReturnValueCallback: Operation
                                                          };
                                            SP.UI.ModalDialog.showModalDialog(options);"
                              EnabledScript="javascript:
                              
var singleItem;

function singleStatusEnable() {
    try{
        var selecteditems = SP.ListOperation.Selection.getSelectedItems();
        var ci = CountDictionary(selecteditems);

        if (ci == 1) {
            return CheckStatus(selecteditems);
        }
        else {
            return false;
        }
    }
    catch (ex) {
        alert('Error occurred: ' + ex.message);
        return false;
    }
}

function CheckStatus(selectedItems) {
    var clientContext = SP.ClientContext.get_current();
    var currentList = clientContext.get_web().get_lists().getById(SP.ListOperation.Selection.getSelectedList());

    var ItemId = selectedItems[0].id;

    if(window.FolderStatusValue === undefined) {
        window.FolderStatusValue = new Array();
    }
    
    if (window.FolderStatusValue[ItemId] === undefined) {
        singleItem = currentList.getItemById(ItemId);
        clientContext.load(singleItem);
        clientContext.executeQueryAsync(Function.createDelegate(this, OnSucceeded), Function.createDelegate(this, OnFailed));
        return false;
    }
    return window.FolderStatusValue[ItemId];
}

function OnSucceeded() {
    
    var selecteditems = SP.ListOperation.Selection.getSelectedItems();
    var ItemId = selecteditems[0].id;

    var ItemStatus = singleItem.get_item('YOUR-CUSTOM-COLUMN-STATIC-NAME');
    
    
    if (ItemStatus) {
        window.FolderStatusValue[ItemId] = true;
        RefreshCommandUI();
    }
    else {
        window.FolderStatusValue[ItemId] = false;
    }
}


function OnFailed(sender, args) {
    alert('Error occurred: ' + args.get_message());
    return false;
}

singleStatusEnable();
" />
      </CommandUIHandlers>
    </CommandUIExtension>
  </CustomAction>
</Elements>


Hope you find this article useful, Happy SharePointing :)

2 comments:

  1. Thank you! This script is just what I needed!

    ReplyDelete
  2. Thanks for the article! Helped a lot!

    ReplyDelete