SharePoint 2007

jQuery to SharePoint Web Services

Recently I have been working on a Google Maps integration for SharePoint and one of the desired capabilities was to include items from SharePoint lists on the map.  The solution was not going to leverage the AJAX .NET capabilites and would instead be built using standard .NET and jQuery.  This presented the major challenge, while we could convert the lists into RSS, GeoRSS, and KML feeds they all required authentication to access these feeds, something that Google Maps does not support in the GGeoXml object.  Google Maps are heavily javascript focused so we couldn’t use the SharePoint API to access the items directly especially since we wanted to avoid post backs to the server, and javascript arrays would likely run out of space give the number of possible items.  This really left us with one possible solution, javascript calls to the SharePoint Web Services.  Fortunately, talking with one of my co-workers he pointed me to a nice, somewhat limited, jQuery plugin for the SharePoint web services available here:

http://www.sympraxisconsulting.com/Demos/Demo%20Pages/SPjQueryWebServices.aspx

Using this service I have been able to access the current web’s lists and items from those lists.  Here is an example of how I have used this plugin to retrieve the lists and populate a selection box, their code for the button clicks are also available.

My Code

$(“.list_select_cell”).html(“<img src=\”/_layouts/images/ewr133.gif\” alt=\”Loading lists\” />”).SPServices({
operation: “GetListCollection”,
completefunc: function(data, status) {
var mySelectBox = “<select size=’5’ id=’list_select’>”;
$(data.responseXML).find(“List”).each(function() {
mySelectBox += “<option value=’” + $(this).attr(“Title”) + “’>” + $(this).attr(“Title”) + “</option>”;
});
mySelectBox += “</select>”;
$(“.list_select_cell”).html(mySelectBox);
}
});

So what is really happening here?

$(“.list_select_cell”).html(“<img src=\”/_layouts/images/ewr133.gif\” alt=\”Loading lists\” />”).SPServices({…

In the above code we have selected a location that currently exists in our page’s DOM and have added the ewr133.gif, the same gif SharePoint uses when processing Site creations.  So basically you specify the DOM object you want to effect while making the asynchronous calls to the SharePoint web service.  You do not have to add or remove text from a DOM object, you could also choose to show or hide an object, that is based on your needs.

operation: “GetListCollection”

Here you are specifying the service you are calling.  These match the name of the asmx file provided by SharePoint, in this case the call is actually going to the GetListCollection.asmx service.  Only certain service calls are supported as the jQuery library is not an all inclusive library.

completefunc: function(data, status) { …

This specifies the action to take when the asynchronous call completes.  The first argument provided to this function is the XmlHttpRequest object, thus in order to gather any information from the response you must parse the responseXML.  At the end of this function I recommend, if you changed the DOM object’s html as part of the “while processing” action that you now set the value to something useful to the user.

So now you can access your lists, and your list items from Javascript and you don’t even need to perform a standard PostBack.

Some limitations

One of the biggest limitations I experienced with this tool is that the plugin assumes you want to use the “current” SharePoint web when retrieveing lists, and also assumes that any list you are accessing is stored in the current web.

Conclusion

This plugin while limited is EXTREMELY stable for an 0.X version, and saved me a number of hours of custom coding WCF services, or building my own version of this plugin.

To Workflow or to Item Event Receive

I was recently asked about how to determine when a List Item should be transferred from one list to another.  Immediately two possible solutions came to mind, use a Workflow or use an Item Event Receiver.  I offered both as “capable” of handling such a need, which of course lead to the next “well which should I use for this…” question and this blog.

Background

SPItemEventReceiver “Provides methods for trapping events that occur to items.”MSDN.  This class generally provides two functions for each action that can occur to an item in a list, eg. ItemAdded and ItemAdding, one that is Synchronous and the other that is Asynchronous.  Custom receivers can be added to lists either programmatically or by ContentType ID.

SPWorkflow “A workflow instance that has run or is currently running on an item.”MSDN. This class is not used like the SPItemEventReceiver because with a workflow we are usually looking at Sequential or State Machine Workflow instances, but I want to remain as generic about the workflows in this article as possible.  This statement does highlight a significant and important difference between the Item Event Receiver and the Workflow, workflows run ON an item but are not necessarily driven BY the item itself.

Before going any further I want to make sure the reader understand that I’m not saying one solution is right and the other is wrong, or that you should only use this solution for this issue.  I also want to be clear in that this is not an either-or approach to solving a problem, in fact the more complex the issue the more you may find the need for both in a “little of this-little of that” solution.  Instead what I have found is that developers often learn one of these two skills and then apply that to everything because it is what they are comfortable with or because it is a new skill and we all like to use our new skills!  Which ever of these cases you fall into I hope this blog will help you understand the benefits of another capability, and save you some time.

SPItemEventReceiver

A SPItemEventReceiver is intended to deal directly with a List Item, either during or immediately after an that item has been involved in an event.  The statement “defining” the SPItemEventReceiver above shows that the SPItemEventReceiver is used to “react to” changes to the item itself.  The Event Receiver is aware of all information stored by an item in the list, and in the ‘ing’ (sychronous) events even exposes the original and new values.

Since the SPItemEventReceiver is designed to interact directly with a list item when a change occurs, actions that are driven by the information it represents are standard candidates for being implemented in the SPItemEventReceiver.  The most common example of this is dealing with records that could be associated with an item that has been deleted from a list.  In this case removing the record association link from all items in the list would be implemented in the asynchronous ItemDeleted event.

My rule of thumb:  Use SPItemEventReceiver when the information in this list item the driver for the event (when you must react).  This may be part or all of the entire information stored by the list item, but in all cases the information in the list item is the MOST IMPORTANT aspect to consider.

SPWorkflow

A SPWorkflow comes in different flavors, but workflows all have one thing in common and that is a “process” by which the workflow will move from beginning to end.  The statements “defining” the SPWorkflow above show that the SPWorkflow is running ON an item.  Therefore the workflow process is typically generic and not oriented to the specific information contained in the actual List Item it is associated with.  This is not to say that the list item’s data is irrelevant, the information may be displayed or modified in one or many of the workflow steps, but the workflow is more oriented toward processing the steps an item must go through to reach a “final” state.

Since the SPWorkflow is designed to progess an item through a series of steps it is mostly concerned with its own state (active/complete), how to move to the next state, and so forth.  Due to this orientation toward step processing of an item, series of actions that will repeat consistently and predictably are candidates for being implemented as Workflows.  The most common example of this is of course the approval process where one or many users/groups must “sign off” on the item before is is approved.

My rule of thumb: Use SPWorkflow when there are a series of steps and actions an item must go through to get from a beginning state to an ending state (when you must cause action).

So what did I recommend for moving the item from one list to another?  First, my question was “How do you determine when to move the item?”.  Based on the answer, “User checks a box on the Edit Item screen” I recommended the SPItemEventReceiver because there was no process for “approving” or determining when to move the item, just a reaction to a List Item’s field.

SharePoint SP2 Bug – 180 Day Countdown

Microsoft recently released the latest service pack for SharePoint 2007 (SP2) which does provide a number of enhancements.  However, in their process of developing this Service Pack they happened to overlook the fact that SP2 resets your SharePoint Installation into a Trial Mode.  What does this mean, basically you have 180 days after installing SP2 to reactivate your SharePoint install as a non-trial version or your SharePoint instance will stop working.  Currently there are no automatic hot fixes for this, but you can re-enter your Product ID on the Convert License Type page which will resolve this issue.

Here is the official statement on the SharePoint blog.

Bamboo List Aggregator Web Part

A customer I support has the Bamboo List Aggregator web part which allows you to consolidate multiple lists into a single view and display on a site, very helpful in SharePoint!  The customer had added one to a page and wanted to be able to set a default “Sort By” and default “Group By” value.  He assumed, as did I went I first looked at this issue, that there would be some very simple option to select a default “Sort By” and “Group By” value, but there wasn’t.  So looking at the web part on the page understanding that Bamboo has simple provided a nice GUI to the Content Query Web Part I knew there was some way to make this work.  So here is how:

Set the Default Sort By Value

  1. Select the “Sort By” value you want to be your default.
  2. Once the page refreshes open the source and search for the value you selected, in this case “Site Path”.  This value will appear multiple times so make sure you find the location in the HTML with the correct Sort By <select> tag and the <option selected> tag.  From there copy the Value of the option tag.
  3. Open the Parameters Editor for the Content Query Web Part and find:
    <ParameterBinding Name=”dvt_sortfield” Location=”Postback;Connection;CAMLVariable” />
    this should be near the top of the parameter edit text box
  4. Add DefaultValue=”<value from option tag in step 2>” (in my example it was DefaultValue=”bsc_SiteProperties”) and then save your changes.
  5. Apply your changes to the web part and verify the field is now defaulted to your desired value.

Set the Default Group By Value

  1. Follow the first two steps in the section above.  Make sure to copy the value from the Group By <select> tag and the<option selected> tag’s Value.
  2. Open the Parameters Editor for the Content Query Web Part and find:
    <ParameterBinding Name=”dvt_groupfield” Location=”Postback;Connection” />
    this should be near the bottom of the parameter edit text box
  3. Add DefaultValue=”<value from option tag>” (in case this was “DefaultValue=”bscListName”) and then save your changes.
  4. Apply your changes to the web part and verify the field is now defaulted to your desired value.

Did You Know – SPQuery DateTime default comparison

After hours of wondering why my code kept reporting scheduling conflicts when I could see events did not overlap I discovered a VERY important note in MSDN on the SPQuery page.
…DID YOU KNOW…

When SPQuery is used to check values against a DateTime field it only checks the Date portion by default? In order to make SPQuery include a time check you must include IncludeTimeValue=’TRUE’ in the Value tag.
Example:

<Value Type=’DateTime’ IncludeTimeValue=’TRUE’><Today/></Value>

Reference:

http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spquery.aspx

Visual Web Part Development

So I readily admit that I am often a code junkie, if I can do it in code then I will. However, I have started to look for tools and solutions that let me code less, drag and drop more, and generate solutions that look better faster.
I have always wanted to experiment with building WebParts using the Visual Studio GUI, but have often found time lacking, until recently. I have a very complex solution that leverages ‘n’ Membership Providers to handle provisioning user information into several different systems (MOSS, AD, OCS, Exchange, Adobe Connect, etc). Working with another developer we initially laid out the solution that would tie all these together, however we quickly realized that we had cut our ability to use the standard .NET Membership Controls. Fortunately, we are able to revisit our designs as we use an iterative approach to our solution development and we have moved back toward the .NET Membership Control support. As such we decided to use the CreateUserWizard control to handle our user creation, however we needed to customize this control…A LOT! Enter visual development of web parts.
We are using the Visual Studio 2008 for development and I initially created a web site project and added a user control to the project. My reason for this is I do not want a code behind page in a SharePoint solution so I will do the initial development and layout in the web project. Because I was using the web project I could use my membership providers to test the compatibility, perform debugging, and just work in a generally scaled down environment.
When I was done with the ascx development, including customization of the look, feel, and actions I copied the ascx into my SharePoint solution. Visual Studio attempted to be helpful by also copying the code behind file, which I deleted. I created a class file in the SharePoint solution and had it inherit from System.Web.UI.UserControl. I copied the functions I had in the code behind page into this class file and saved it. I then changed the <%@ Control … line so that rather than referencing a code behind file I inherited from the class I had just added to the SharePoint solution. Finally, for the code where I referenced controls on the ascx I included protected controls in the class file (if you forget this step the compiler will remind you).
Once I had the ascx and the class file included in my SharePoint solution I added a WebPart class that simply called the Page.LoadControl(…) and passed the relative path to my ascx user control. The Page.LoadControl returns a Control object which I then added to the Controls of my WebPart.
That was it, I loaded the solution and added the web part to the page. As soon as it was added the part displayed exactly as expected and functioned just like it had in the web site project. Total time for this was about 30 minutes, which if I had tried to create the wizard in code and customize the template would probably have taken most of a day, if not multiple days.