Second Life of a Hungarian SharePoint Geek

April 8, 2011

Using ECMAScript Client Object Model from ECB Custom Actions

For MOSS 2007 / WSS 3.0 one could use JavaScript in Edit Control Block (EBC) custom action as described in this article by Jan Tielens. For SharePoint 2010 it is now even easier to achieve similar results with the ECMAScript Client Object Model.

In my test project I’ve created a simple custom content type, having a Title and a number-typed field called Numeric, a list definition and a list instance including sample data and bound the custom actions to the content type.

The deployed list called Test List Instance looks like this:

image

The next step is to create the JavaScript file and bind it to the pages. It can be done using a CustomAction with the Location value ScriptLink, as shown here:

  1. <?xmlversion=1.0encoding=utf-8?>
  2. <Elementsxmlns=http://schemas.microsoft.com/sharepoint/>
  3.   <CustomAction
  4.       Location=ScriptLink
  5.       ScriptSrc=JCOMCustomAction/CustomAction.js
  6.       Sequence=100 />
  7. </Elements>

Unfortunately, in this case you cannot use RegistrationType nor RegistrationId to specify the items your custom action is bound to.

The JavaScript file itself and the images we use for the ECB custom actions are added to the project through mapped folders:

image

In this sample I’ve created two actions, one to query the field values of the current item, and another one to reset the Numeric field value to zero for the current item.

First, let’s see the custom action definition of the “getter” method.

  1. <?xmlversion=1.0encoding=utf-8?>
  2. <Elementsxmlns=http://schemas.microsoft.com/sharepoint/>
  3.   <CustomActionDescription=JavaScript Client Object Model Get Item Data Custom Action
  4.               Id=JCOMCustomAction.GetItemData
  5.               Location=EditControlBlock
  6.               ImageUrl=/_layouts/images/JCOMCustomAction/question.png
  7.               Sequence=1000
  8.     Title=Get Item Data
  9.     RegistrationType=ContentType
  10.     RegistrationId=0x0100e36db888927049468d7cbaf1c7b70582>
  11.     <UrlActionUrl=javascript:getItemById(‘{ListId}’, {ItemId})/>
  12.   </CustomAction>
  13. </Elements>

We call the getItemById JavaScript method with two parameters, {ListId} for the list ID (GUID value passed as string, so we should use apostrophes) and {ItemId} (this one is a plain numeric value) for item ID of the current item. Both of these parameters are tokens and will be replaced by the actual values.

In the corresponding JavaScript block we check first if there is another request in progress, and if there is not, then we query the field values in an asynchronous ECMAScript client object call.

  1. var item;
  2. var inProgress = false;
  3. function getItemById(listId, listItemId) {
  4.     if (inProgress) {
  5.         alert(“Another request is in progress. Try again later!”);
  6.     }
  7.     else {
  8.         try {
  9.             inProgress = true;
  10.             var context = new SP.ClientContext.get_current();
  11.             var web = context.get_web();
  12.             var list = web.get_lists().getById(listId);
  13.             this.item = list.getItemById(listItemId);
  14.             context.load(this.item, “Title”, “Numeric”);
  15.             context.executeQueryAsync(Function.createDelegate(this, this.itemReceived), Function.createDelegate(this, this.failed));
  16.         }
  17.         catch (e) {
  18.             alert(“Error: “ + e);
  19.             inProgress = false;
  20.         }
  21.     }
  22. }
  23. function itemReceived() {
  24.     gotItem(this.item);
  25.     inProgress = false;
  26. }
  27. function failed(sender, args) {
  28.     alert(“Operation failed: “ + args.get_message());
  29.     inProgress = false;
  30. }
  31. function gotItem(item) {
  32.     alert(“Title: “ + item.get_item(“Title”) + “\r\nNumeric: “ + item.get_item(“Numeric”));
  33. }

Selecting the menu item in the ECB and the results shown below.

image

image

The custom action definition and the “setter” method is very similar to the former one.

  1. <?xmlversion=1.0encoding=utf-8?>
  2. <Elementsxmlns=http://schemas.microsoft.com/sharepoint/>
  3.   <CustomActionDescription=JavaScript Client Object Model Set Item Data Custom Action
  4.               Id=JCOMCustomAction.SetItemData
  5.               Location=EditControlBlock
  6.               ImageUrl=/_layouts/images/JCOMCustomAction/exclamation.png
  7.               Sequence=1000
  8.     Title=Set Item Data
  9.     RegistrationType=ContentType
  10.     RegistrationId=0x0100e36db888927049468d7cbaf1c7b70582>
  11.     <UrlActionUrl=javascript:setItemById(‘{ListId}’, {ItemId})/>
  12.   </CustomAction>
  13. </Elements>

After a successful update, we have to refresh the page content to show the change. I achieved that simple by reloading the entire page. Some kind of AJAX-refresh would be definitely better here, but I have not yet found the right way to force that.

  1. function setItemById(listId, listItemId) {
  2.     if (inProgress) {
  3.         alert(“Another request is in progress. Try again later!”);
  4.     }
  5.     else {
  6.         try {
  7.             inProgress = true;
  8.             var context = new SP.ClientContext.get_current();
  9.             var web = context.get_web();
  10.             var list = web.get_lists().getById(listId);
  11.             this.item = list.getItemById(listItemId);
  12.             context.load(this.item);
  13.             item.set_item(“Numeric”, 0);
  14.             item.update();
  15.             context.executeQueryAsync(Function.createDelegate(this, this.itemUpdated), Function.createDelegate(this, this.failed));
  16.         }
  17.         catch (e) {
  18.             alert(“Error: “ + e);
  19.             inProgress = false;
  20.         }
  21.     }
  22. }
  23. function itemUpdated() {
  24.     inProgress = false;
  25.     window.location.href = window.location.href;
  26. }

Selecting the setter menu item in the ECB and the results shown below. Notice the zero value of the Numeric field for the updated item.

image

image

You can download the sample project from this location.

4 Comments »

  1. This is a great post. I now have a much better understanding of how to use EcmaScript with the ribbon. I am currently working on a solution that requires me to add a custom button to the ribbon that will allow a user to update a field in a custom list for all list items that are selected. If you could advise me on how to accomplish thhis it would be greatly appreciated.

    Comment by mtmikel — July 11, 2011 @ 20:20

  2. Hi Peter,

    I see that you the Title attribute is hard-coded:

    Sequence=”1000″ Title=”Get Item Data” RegistrationType=”ContentType”

    How can you make this dynamic based on the properties of the associated list item? Similar to the context menu for a Document, where we see either “Check In” or “Check Out”,

    Thanks,
    Mike

    Comment by Mike — October 29, 2012 @ 16:47


RSS feed for comments on this post. TrackBack URI

Leave a reply to Mike Cancel reply

Create a free website or blog at WordPress.com.