basquang™ on clouds

October 15, 2010

Building batch approval ribbon in SharePoint 2010

Filed under: ECMAScript,SharePoint,SPServices — basquang @ 10:21 AM

In SharePoint 2010, We can delete multiple items but cannot with approve/reject items. So, how can user approve/reject multiple items in one time? For example TimeSheet application in SharePoint. We can create custom Ribbon then using Application page as dialog and SharePoint Server-Side object model to solve that problem. To complete your function, you have to resolve following things:

1. How we pass the selected items and list to dialog page? We use ECMAScript as following script in CommanAction funtion of the ribbon button

// Shows custom dialog using SharePoint Client JS OM
function RibbonButtonHandler() {
    var ctx = SP.ClientContext.get_current();
    var items = SP.ListOperation.Selection.getSelectedItems(ctx);
    var myItems = '';
    var k;

    for (k in items) {
        myItems += '|' + items[k].id;
    }
    var options = {
        url: "/_layouts/BatchApprovalRibbon/UI/ApproveRejectPage.aspx?items=" + myItems + "&list=" + SP.ListOperation.Selection.getSelectedList(),
        width: 600,
        height: 400,
        dialogReturnValueCallback: demoCallback
    };

    SP.UI.ModalDialog.showModalDialog(options);
}

By passing selected items and list as text in url parameter, we can easy to get those in application page by Request.QueryString

2. In Application Page dialog, how can We approve/reject item programmatically? We cannot use item[“Approval Status”] = “approved”, we must use following scripts instead.

SPListItem item = currentList.GetItemById(Int32.Parse(id));
SPModerationInformation approvalStatus = item.ModerationInformation;
approvalStatus.Status = status;
approvalStatus.Comment = comments;
item.Update();

with status is SPModerationStatusType.

3. After approve/reject Items, how can we close dialog page and refresh parent page?

First we must close  the dialog page in server-side code:

protected void CloseDialogPage()
    {
      Context.Response.Write("<script type='text/javascript'>window.frameElement.commitPopup();</script>");
      Context.Response.Flush();
      Context.Response.End();
    }

Then we call SP.UI.ModalDialog.RefreshPage(SP.UI.DialogResult.OK) in dialogReturnValueCallback function as following

function demoCallback(dialogResult, returnValue) {
    SP.UI.Notify.addNotification('Operation Successful!');
    SP.UI.ModalDialog.RefreshPage(SP.UI.DialogResult.OK);
}

Now You can use your ribbon to process batch approve/reject items.

clip_image002

4. But I think we should consider how to enable/disable your ribbon by condition or context. To Enable/Disable ribbon button, we use EnabledScript attribute in CommandUIHandler element in you ribbon custom action

<CommandUIHandler
    Command="Ribbon.Approval.Batch Approval.Button_CMD"
    EnabledScript="javascript:EnableRibbonButton();"
    CommandAction="javascript:RibbonButtonHandler();" />

And in javascript funtion, in my scenario, we want to disable the button when there isn’t any items has selected and will enable for special list only. We use following script

function EnableRibbonButton() {
    var items = SP.ListOperation.Selection.getSelectedItems();
    var ci = CountDictionary(items);
    var listId = SP.ListOperation.Selection.getSelectedList();
    if (ci > 0 && listId == '{A32BC151-5396-4377-AFB3-B769668C3A83}') {
        return true;
    }
    return false;
}

Finally: NOTE

Keep in mind that we pass url: “/_layouts/BatchApprovalRibbon/UI/ApproveRejectPage.aspx…. It mean dialog page will called under top level sie context. So SPContext.Current always return top level site. So if You use this ribbon in subsite, You should get error message “the list does not exist”. To resolve it, We can

– change the url to: url: “/[your subsite]/_layouts/…

– In Code behind, does not use SPContext.Current.Web directly, we must find the exactly the web of the list instead. We was use

SPSite site = SPContext.Current.Site;
      foreach (SPWeb web in site.AllWebs)
      {
        currentList = SearchListById(web, listGuid);
        if (currentList != null)
        {
         //Update list item
          break;//break foreach
        }
      }
SPList SearchListById(SPWeb web, Guid listId)
    {
      foreach (SPList list in web.Lists)
      {
        if (list.ID.Equals(listGuid))
        {
          return list;
        }
      }
      return null;
    }

Hope this help!

October 14, 2010

ECMAScript: SP.ClientContext is undefined or null

Filed under: ECMAScript,SharePoint — basquang @ 9:26 AM

Sometime We cannot use SP.ClientContext in Site pages, Web part pages or Application pages. Although We was following this guide from msdn

Setting Up an Application Page for ECMAScript

If so, please replace the below lines

<script type=”text/ecmascript” src=”/_layouts/SP.Core.js” />
<script type=”text/ecmascript” src=”/_layouts/SP.Debug.js” />
<script type=”text/ecmascript” src=”/_layouts/SP.Runtime.Debug.js” />

With

<SharePoint:ScriptLink ID=”ScriptLink1″ Name=”sp.debug.js” LoadAfterUI=”true” Localizable=”false” runat=”server” />

Reference MSDN

Blog at WordPress.com.