Showing posts with label Enable button. Show all posts
Showing posts with label Enable button. Show all posts

Tuesday, June 14, 2011

How to enable/disable buttons in ribbon conditionally?

In this article I will cover how we can enable and disable the controls from ribbon based on any specific column value. For an instance I have a list column "State", if selected row is having status "active" then and then button should be enable in Ribbon, otherwise ribbon button should remain disable.

For how to write Ribbon declaration please refer my previous articles.


In above image you can see we have one button "New" in ribbon within group "Console". Please refer the source code for Ribbon's declaration. We are going to use delegate control for injecting ECMA script on fly for desired list.
Below are the events causes ribbons to refresh so button can be turned enable/disable.
  • Checkbox from every row
  • SelectAll/DeselectAll checkbox from header row
  • On every row select
On each of above events after executing their respective functionality they instruct the ribbon to refresh. On received of refresh event ribbon calls Enable script for each of its control. Enable Script is the attribute which points to JavaScript function which can contain the logic for deciding button to be enabled or disable. You can mention the JavaScript function name to Enable Script attribute while declaring the Ribbon XML element.
Now let's see how sample is going to work.
  • On page loads and when no row is selected button will be disable
  • When user clicks checkbox of row and that row is having "Active" as status value then button will get enable
  • When user clicks row and that row is having "Active" as status value then button will get enable
  • If row is selected and button is enable and user click select all checkbox then ribbon will get refresh and button will be disable
So to achieve required functionality what we need is,
  • A function which will return a Boolean flag for ribbon to enable/disable button
  • We need to attach our own events on row click, row checkbox click and header checkbox click
  • So in our own functions we will retrieve the row and it's all cell values
  • Based on status cell value we will set the global flag true/false.
  • Then we will call Ribbon refresh, which eventually will enable/disable the button
Let's see how we can attach our own functions to various click events,


var _isButtonEnable = false;
var statusIndex = 2;
var row;

_spBodyOnLoadFunctionNames.push("registerEvents");

function isButtonEnablefn() {
    if (_isButtonEnable != 'undefined')
    { return _isButtonEnable } else
        return false;
}

function registerEvents() {
    var ctxCur = GetCurrentCtx();
    var SPGridViewGuid = ctxCur.listName;
    var oTables = document.getElementsByTagName("TABLE");
    for (var i = 0; i < oTables.length; i++) {
        if (oTables[i].id != "") {
            var listGUID = oTables[i].id.split("-{");
            if (listGUID[0] == SPGridViewGuid) {
                var oRows = oTables[i].getElementsByTagName("TR");

                var chkbxs = oRows[0].getElementsByTagName('input');
                if (chkbxs != null) {
                    chkbxs[0].attachEvent('onclick', selectAllClicked);
                }

                for (var j = 0; j < oRows.length; j++) {
                    if (j != 0) {
                        oRows[j].attachEvent('onclick', rowClicked);
                        var chkbx = oRows[j].getElementsByTagName('input');
                        if (chkbx != null) {
                            chkbx[0].attachEvent('onclick', rowCbxClicked);
                        }
                    }
                }
            }
        }
    }
}

function selectAllClicked() {
    _isButtonEnable = false;
    RefreshCommandUI();
}

function rowClicked() {
    setSelectedItem();
}

function rowCbxClicked() {
    setSelectedItem();
}

function setSelectedItem() {
    var evt = null;
    //capture the curren event
    evt = window.event;
    //retrieve the source of event
    var o = GetEventSrcElement(evt);
    //if source element is ECB menu or link then return don't do anything
    if (o != null && ElementContainsLink(o))
        return;
    // Close ECB menu if it is already open   
    if (clearECBMenu(o)) {
        CancelEvent(evt);
        return false;
    }
    //Retrieve the Row from which the event has raised
    var tr = GetItemRow(evt);
    var ctxCur = CtxFromRow(tr);

    if (CountSelectedItems(ctxCur) == 1) {
        var items = GetSelectedItemsDict(ctx);
        var k
        for (k in items) {
            var itm = items[k];
            //alert('List GUID :' + ctxCur.listName + '-- Item ID:' + itm.id);
            // Keep selected row in backstore we will need this later on in ribbon events
            var curRow = saveCurrentRow(tr, itm.id);
            // If Row Item Status is Active then turn on New Button.
            (curRow.cells[statusIndex].outerText == SP.MyResource.Active) ? _isButtonEnable = true : _isButtonEnable = false;
        }
    }
    else { _isButtonEnable = false; }
    RefreshCommandUI();
}

function saveCurrentRow(tr, curSelectedItemId) {
    var tab = tr;
    while (tab.tagName != "TABLE")
        tab = tab.parentNode;
    var rows = tab.rows;
    var i = 0;
    //This loop will fix the index for Phase State
    for (i = 0; i < tab.cells.length; i++) {
        if (tab.cells[i].outerText.trim() == SP.MyResource.State.trim()) {
            statusIndex = i;
            break;
        }
    }
    var iid;
    var rgiid;
    //This loop will fix the current selected row
    for (i = 1; i <= rows.length; i++) {
        iid = rows[i].getAttribute("iid");
        rgiid = iid.split(",");
        if (rgiid[1] == curSelectedItemId) {
            if (typeof (row) == "undefined") row = [];
            row[curSelectedItemId.id] = rows[i];
            return rows[i];
        }
    }
    return null;
}

function NewButtonClick() {
    var url;
    var ctxCur = GetCurrentCtx();
    if (CountSelectedItems(ctxCur) == 1) {
        var items = GetSelectedItemsDict(ctx);
        var item
        for (item in items) {
            var itm = items[item];
            alert('List GUID :' + ctxCur.listName + '-- Item ID:' + itm.id);
        }
    }
}

// javaScript String object's extension method for trim operation
String.prototype.trim = function () {
    return this.replace(/^\s*/, "").replace(/\s*$/, "");
}

Tuesday, March 29, 2011

Enabling a Button on the Ribbon Based on Selection

Enabling a Button on the Ribbon Based on Selection

A lot of people have asked me how to create a button which enables if and only if a single item is selected. This isn’t something we have out of the box, but the code to get this functionality is pretty simple. I’m going to assume that you’re generally familiar with SharePoint, CustomActions, and customizing the Ribbon – if that’s not the case, you’d probably be better off researching those things before delving into this.
Basically, the enabling behavior all boils down to the following few lines of code:

EnabledScript="javascript:function singleEnable() {   var items =
   
SP.ListOperation.Selection.getSelectedItems();   var ci = CountDictionary(items);   return (ci == 1); } singleEnable();"

What this does is query to get the dictionary of selected items, and if the size of the dictionary is 1 it returns true (enable), otherwise it will return false (disable). Technically, I should have used Script on Demand to call into the SP.* namespace, but since I’m calling this from the Ribbon I have a high confidence that SP.js has been loaded already.

With nothing selected:

image

With one item selected:

image

Clicking the button:

image

And with more than one item selected:

image

You could also change this to enable only if no items were selected, or if any number of items were selected. The way to make those kinds of changes should be relatively self-explanatory.
The full CustomAction code for a sample Ribbon button which enables when one item is selected is at the end of this post. The code assumes the following:
  1. You want to add this button to the New group on the Documents tab. If you want to add the button to another location, you should change the Location attribute of the CommandUIDefinition element (as well as change any appropriate attributes in the Button element, such as Id and Sequence, to match the new location).
  2. You have an icon image at LAYOUTS/SharePointProject1/DemoButton.jpg. If that’s not the case, you should either put an icon at that location or change the Image32x32 attribute to a valid icon path.

CustomAction code:

<CustomAction   Id="EnableSingleSelectButton"   Location="CommandUI.Ribbon" >   <CommandUIExtension>     <CommandUIDefinitions>
     
<CommandUIDefinition   Location="Ribbon.Documents.New.Controls._children">   <Button Id="Ribbon.Documents.New.EnableSingleSelectButton"           Alt="Button enabled on single selection"           Sequence="35"           LabelText="Single Select"
 
Image32by32="/_layouts/SharePointProject1/DemoButton.png"           Command="SingleSelectButton"           TemplateAlias="o1" />       </CommandUIDefinition>     </CommandUIDefinitions>     <CommandUIHandlers>       <CommandUIHandler           Command="SingleSelectButton"           CommandAction="javascript:alert('There is only one thing selected!');"           EnabledScript="javascript:function singleEnable()
          {
            var items = SP.ListOperation.Selection.getSelectedItems();             var ci = CountDictionary(items);             return (ci == 1);           }           singleEnable();" />     </CommandUIHandlers>   </CommandUIExtension> </CustomAction>