Approve/Reject Multiple Items of List in SharePoint 2010

You can approve/Reject an item from SharePoint ribbon. But only one item can be approved or rejected. But I’ve found requirements from few of my clients that they want to approve/reject in batch rather than one by one. This is logical. If there’s 100 of items to approve/reject, doing this one by one is tedious. In this post I’ve described how I’ve implemented the idea and at the end of the blog you can find the link to download the source code.

My approach to allow multiple approve/reject in batch is following the steps:

  • Add a new ribbon “Approve/Reject Selection” as shown below. The new ribbon will be active when more than one item will be selected.

Approve/Reject Multiple Items of List in SharePoint 2010 

Figure 1: New ribbon “Approve/Reject Selection” added

  • When multiple item will be selected from grid the “Approve/Reject Selection” will be active as shown below:
  • Approve/Reject Multiple Items of List in SharePoint 2010

    Figure 2: “Approve/Reject Selection” will be active when multiple items will be selected

    Clicking on “Approve/Reject Selection” will bring up a new custom window developed my me as shown below:

    Approve/Reject Multiple Items of List in SharePoint 2010 

    Figure 3: Approve/Reject Multiple items dialog

    • Finally, the custom dialog shown in figure 3, is an application page where we need to write code to approve/reject selected items programmatically.

    So let’s start with the process of implementing the idea!!!!!!!!!!!

    Step 1: Create a custom ribbon

    First add a new empty element as shown below:

    Approve/Reject Multiple Items of List in SharePoint 2010

    Figure 4: Add new empty element

    Then add the following xml in the elements.xml file:

    <?xml version="1.0" encoding="utf-8"?>
    <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
    <CustomAction Id="COB.SharePoint.Ribbon.NewControlInExistingGroup" Location="CommandUI.Ribbon.ListView" RegistrationType="List" RegistrationId="100">
    <CommandUIExtension>
    <CommandUIDefinitions>
    <CommandUIDefinition Location="Ribbon.ListItem.Workflow.Controls._children">
    <Button Id="COB.SharePoint.Ribbon.NewControlInExistingGroup.Notify" Command="COB.Command.NewControlInExistingGroup.Notify" Sequence="21" Image16by16="/_layouts/$Resources:core,Language;/images/formatmap16x16.png" Image16by16Top="-48" Image16by16Left="-240" Image32by32="/_layouts/$Resources:core,Language;/images/formatmap32x32.png" Image32by32Top="-448" Image32by32Left="-384" Description="Uses the notification area to display a message." LabelText="Approve/Reject Selection" TemplateAlias="o1"/>
    </CommandUIDefinition>
    </CommandUIDefinitions>
    <CommandUIHandlers>
    <CommandUIHandler Command="COB.Command.NewControlInExistingGroup.Notify" EnabledScript="javascript:enableApprovalAll();" CommandAction="javascript: showApproveAll(); "/>
    </CommandUIHandlers>
    </CommandUIExtension>
    </CustomAction>
    <CustomAction Id="COB.Command.NewControlInExistingGroup.Notify.Script" Location="ScriptLink" ScriptSrc ="/_layouts/SharePoint.ApproveRejectTest/Scripts/ApproveReject.js"/>
    </Elements>







    Figure 5: Code snippet for Custom Ribbon



    I’m not going to describe the code snippet at figure 5 elaborately. However the basic things are that, I’m adding a button with label “Approve/Reject Selection” and I’ve associated two commands with the button. One is when to enable/disable the button with CommandUIHandler’s EnableScript attribute. The buttton click event action is defined with CommandAction attribute. If you notice I’ve just mentioned two javascript function enableApproveAll and showApproveAll. These two functions are not defined in this xml. Rather they are defined in another file “/_layouts/SharePoint.ApproveRejectTest/Scripts/ApproveReject.js” which is referenced in xml file.



    Step 2: Create the script file to show/hide approve/reject dialog


    The content of the ApproveReject.js file is show below. The command to show the approve/reject dialog is declared in this script. The function showApproveAll() will show a custom application page that I’ve described in step 3. The reference section in the file helps to get intellisense. I’ve not explained the script that much as it’s not in the scope of this post.




    function showApproveAll() 
    {
    var ctx = SP.ClientContext.get_current();
    var ItemIds = "";
    //get current list id
    var listId = SP.ListOperation.Selection.getSelectedList();
    //get all selected list items
    var selectedItems = SP.ListOperation.Selection.getSelectedItems(ctx);
    //collect selected item ids
    for (var i = 0; i < selectedItems.length; i++)
    {
    ItemIds += selectedItems[i].id + ",";
    }
    //prepare cutom approval page with listid
    //and selected item ids passed in querystring
    var pageUrl = SP.Utilities.Utility.getLayoutsPageUrl('/SharePoint.ApproveRejectTest/ApproveAll.aspx?ids=' + ItemIds + '&listid=' + listId);
    var options = SP.UI.$create_DialogOptions();
    options.width = 420;
    options.height = 250;
    options.url = pageUrl;
    options.dialogReturnValueCallback = Function.createDelegate(null, OnDialogClose);
    SP.UI.ModalDialog.showModalDialog(options);
    }
    //used to determine whether the 'approve/reject selection'
    //ribbon will be enalbed or disabled
    function enableApprovalAll()
    {
    var ctx = SP.ClientContext.get_current();
    return SP.ListOperation.Selection.getSelectedItems(ctx).length > 1;
    }
    //called on dialog closed
    function OnDialogClose(result, target)
    {
    //if ok button is clicked in dialog, reload the grid.
    if (result == SP.UI.DialogResult.OK)
    {
    location.reload(true);
    }
    }







    Figure 6: ApproveReject.js file





    In the method showApproveAll, I’ve collected the selected Items’ IDs and passed to “ApproveAll.aspx” page as querystring. I’ve also passed the current list id in querystring.



    Step 3: Create custom Approve/Reject application page


    Finally I’ve developed a application page named as “ApproveAll.aspx”. The partial markup of the page is shown below:




    <asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
    <script type="text/javascript">
       1:  
       2:         function closeDialog() 
       3:         {
       4:             SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel, 'Cancelled clicked');
       5:         }
       6:         function finisheDialog() 
       7:         {
       8:              SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK, 'Cancelled clicked');
       9:          }
      10:     
    </script>
    <h2 id="divMessage" runat="server"> </h2>
    <table>
    <tr>
    <td> Status: </td>
    <td>
    <asp:DropDownList ID="ddlAprovalOptions" runat="server">
    <asp:ListItem Text="Approve" Value="Approved" />
    <asp:ListItem Text="Pending" Value="Pending" />
    <asp:ListItem Text="Reject" Value="Denied" />
    </asp:DropDownList>
    </td>
    </tr>
    <tr>
    <td> Comments: </td>
    <td>
    <asp:TextBox ID="txtComments" runat="server" TextMode="MultiLine" Columns="40" Rows="5" MaxLength="255" />
    </td>
    </tr>
    <tr>
    <td> </td>
    <td>
    <asp:Button ID="btnSubmit" runat="server" Text="OK" OnClick="btnOk_Click" />
    <input type="button" runat="server" id="btnCancel" value="Cancel" onclick="closeDialog()" />
    </td>
    </tr>
    </table>
    </asp:Content>





    Figure 7: ApproveAll.aspx page’s markup





    In the code behind of the page, you need to extract the list id and list item ids. Then you need to invoke a method like shown below to approve/reject items:



     




    private void ApproveRejectItems(SPWeb web, string listId, SPModerationStatusType moderationStatusType, List<int> itemIDs)
    {
    web.AllowUnsafeUpdates = true;
    SPList spList = web.Lists[new Guid(listId)];
    foreach (var itemId in itemIDs)
    {
    SPListItem spListItem = spList.GetItemById(itemId);
    //disable workflow
    foreach (SPWorkflow workflow in spListItem.Workflows)
    {
    if (workflow.ParentAssociation.Id == spList.DefaultContentApprovalWorkflowId)
    {
    SPWorkflowManager.CancelWorkflow(workflow);
    }
    }
    //update moderation status
    spListItem.ModerationInformation.Comment = txtComments.Text;
    spListItem.ModerationInformation.Status = moderationStatusType;
    spListItem.Update();
    }
    }





    Figure 8: Approve/Reject items



    As shown in the code snippet in figure 8, first we need to make sure we disable content approval workflow, if exists. Then we can update the moderation status.



    The full source code can be download from My Skydrive.