In the previous post I wrote about having a custom ribbon button which handles a postback event. In the conclusion I also wrote that so far I haven’t been able to figure out how to retrieve the selected item when the postback occurs. So I have been looking at alternatives to implement what I want, and decided to go with the new client object model so that I don’t need a postback anymore.
First, we need to create a new empty SharePoint element in your SharePoint 2010 project in Visual Studio. The contents of the file is as following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <?xml version="1.0" encoding="utf-8"?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <CustomAction Id="TicketResolvedRibbonCustomAction" RegistrationId="28582" RegistrationType="List" Location="CommandUI.Ribbon" Rights="ManageLists" Sequence="25" Title="Mark as Resolved"> <CommandUIExtension> <CommandUIDefinitions> <CommandUIDefinition Location="Ribbon.ListItem.Actions.Controls._children"> <Button Id="TicketResolvedRibbonButton" Alt="Mark this ticket as resolved." Description="Mark this ticket as resolved." Sequence="25" Command="ResolveTicketCommand" Image32by32="/_layouts/images/Homburg.TicketDesk/ticketresolved.png" LabelText="Mark as Resolved" TemplateAlias="o1" /> </CommandUIDefinition> </CommandUIDefinitions> <CommandUIHandlers> <CommandUIHandler Command="ResolveTicketCommand" EnabledScript="javascript: function enableResolveTicketButton() { var items = SP.ListOperation.Selection.getSelectedItems(); return (items.length == 1); } enableResolveTicketButton();" CommandAction="javascript:TicketDeskMarkTicketAsResolved('{SelectedItemId}');" /> </CommandUIHandlers> </CommandUIExtension> </CustomAction> <Control Id="AdditionalPageHead" ControlSrc="~/_controltemplates/TicketResolvedRibbonDelegate.ascx" Sequence="25"/> </Elements> |
So, compared to the element in my previous post, you’ll now notice that there is a CommandUIHandlers element and I’ve specified a couple of things. First, I want to make sure that the button is only available when an item is actually selected. That’s where the EnabledScript attribute is for.
The CommandAction attribute specifies the JavaScript method that will be called when the button is clicked. In this case, it’s a method that’s defined in the user control that’s linked at the bottom of the XML definition. Now you can use some predefined parameters in your method calls, one of them being the ID of the current selected item: {SelectedItemId}.
Next, we need the user control, so create a new user control in the SharePoint CONTROLTEMPLATES folder in Visual Studio. In this case, we won’t be needing anything in the code-behind file, everything occurs in the ASCX file itself.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | <SharePoint:ScriptLink Name="SP.js" runat="server" LoadAfterUI="true" Localizable="false" /> <SharePoint:FormDigest ID="FormDigest1" runat="server" /> <script language="ecmascript" type="text/ecmascript"> var ticketsList; var web; var context; var ticketId; var ticketItem; var ticketStatusField = "TicketStatus"; var ticketDoneStatus = "Done"; var ticketResolvedStatus = "OK"; function TicketDeskMarkTicketAsResolved(itemId) { ticketId = itemId; context = new SP.ClientContext.get_current(); web = context.get_web(); ticketsList = web.get_lists().getByTitle("Tickets"); ticketItem = ticketsList.getItemById(ticketId); // This will make sure the contents of the list and list item are actually loaded context.load(ticketsList); context.load(ticketItem); context.executeQueryAsync(OnTicketsListsLoaded); } function OnTicketsListsLoaded() { var currentStatus = ticketItem.get_item(ticketStatusField); // There's no need to continue this method when the status is already set to resolved or the ticket has been completed. if (currentStatus == ticketResolvedStatus || currentStatus == ticketDoneStatus) { return; } // Set the ticket status field to the Resolved value ticketItem.set_item(ticketStatusField, ticketResolvedStatus); ticketItem.update(); // Submit the query to the server context.load(ticketItem); context.executeQueryAsync(OnTicketUpdated, OnError); } function OnTicketUpdated(args) { // Nothing really needed here other than refreshing the page to see that the change has been made window.location.href = window.location.href; } function OnError(sender, args) { alert(args.get_message()); } </script> |
Going through the code, we see a couple of things. First we need a reference to SP.js, so we can actually use the client object model. The FormDigest tag is there so we can perform an update of a list item.
I’m declaring a couple of variables so I can use those in the various methods I have. The first method is the one that’s being called from the XML element created in the first step.
In this method, I’m setting the context that’s used to retrieve the web and list we’re working with. Based on the ID that’s supplied, I’m loading the list item on which the update should be performed. The list and list item are then loaded in the context after which a query is executed asynchronously, to retrieve the data. A callback method is defined for when the query has completed.
In the callback method, I’m doing a couple of checks to see whether an update is required. Then, by using set_item(), you can specify the field name and the value to update an item. The context is loaded again with the updated item and the update query is submitted to the server.
This is a very simple example of how to use the SP2010 client object model to perform an update on a list item. This can easily be extended with more complex business logic, to suit other needs.
Thanks Dennis, this was really helpful – needed something pretty much just like this. Happen to have updated it to support changing multiple selected items by chance?
Glad it was helpful to you. Unfortunately I haven’t spent any more time to get it working with multiple items, as it was not really a requirement back then to implement something like that. Sounds like an interesting feature though, I’ll update this post should I come across something like it
I needed this topic because i knew we can use SP2010 client object model to update a list item but i do not know the code to implement it. Thanks for this blog team to give such an useful post with code. I will read your blog regularly hearafter. Thanks for your effort.
http://gloriatech.com/microsoft-net-development-services.aspx
Just wanted to say thanks. Most examples on the net I found all referred to {ItemId} to get the reference to the listitem.
You’re the first I found that mentioned {SelectedItemId}. One less issue to contend with, so thanks heaps.
Using __doPostBack(”, getParams());” /> will post the selected items back to the server… where getParams() is your function that deals with formatting the selected values – which function will probably end up calling SP.ListOperation.Selection.getSelectedItems() and enumerate…
Thanks for the articles though, very nicely put together!
Cool, thanks for sharing that. I haven’t really played with this since writing this blog post, but I’ll be sure to keep that in mind. And thanks for the compliment