Wednesday, November 26, 2008

jQuery in a SharePoint Custom Field

One way of gaining new SharePoint functionality without "disturbing" the structure or content of lists and document libraries is to create custom fields that use jQuery to perform client-side processing.

AJAX calls to the built-in web services are simple once the SOAP message structure has been determined. The data returned by the call can then be made to interact with and modify controls on the page using the powerful selector mechanism in jQuery.

In this post I'll cover a few tips I learnt whilst creating one such custom field.

The Ajax Call

In a previous post I covered the structure of a jQuery AJAX call to a SharePoint web service. But how to derive the actual SOAP body for that call? One way I found to do this which removed lots of the guess work was as follows:
  1. Create a simple console application in Visual Studio and add a reference to the web service you want to call

  2. Write code in that console application to call the required method on that web service. Begin by using the simplest set of parameters in the call and making sure they return data as expected before adding additional parameters. For example, in my calls to the Lists web service (lists.asmx) my first tests used empty elements for the query, viewfields and queryoptions arguments in the GetListItems() call

  3. Start up Fiddler (or your favourite HTTP traffic logging tool). Ensure that the "Capture Traffic" option is ticked in the file menu.

  4. Run your console application, which will make the web service call.

  5. In Fiddler, view the HTTP call that was made by the console app by clicking on that listed call - it will be to the URL you set in the console app, and will have a result of '200'.

If the right-hand pane of Fiddler is showing the Statistics tab, click on the Inspectors tab - this displays the outgoing message from your console app in the top half, and the return message in the bottom half. Open the Raw tab within each half of the right-hand pane, and you will see the soap envelope that was sent in the web service call in the top pane. That is the XML to be used in the data parameter of the jQuery AJAX call.

One other item to note from the Raw content of the outgoing HTTP call is the SOAPAction, as that value needs to be used to set the soapaction in the beforesend anonymous function in the jQuery AJAX call.

Communicating from SharePoint to jQuery
One important point I have not yet covered was the fact that it is possible for a custom field to render in a SharePoint form, and yet to have no displayed elements. This is one way to use jQuery to modify controls and data in the form. My custom field outputs only script tags plus an empty span. It is still necessary to hide the table row in the form that contains this custom field, as the standard SharePoint rendering of a field in the new/edit list item form shows the field title in the left column and the field content in the right.

Hiding of the row is achieved by giving the empty span a class (for example 'hiddenfield'), and then rendering in the custom field some jQuery script that hides table rows that contain spans with the 'hiddenfield' class.

For the custom field to interact with data in other fields using jQuery, data needs to be passed from the server side into the client-side script in the custom field. AJAX web service calls can be used for this once the form has rendered, but what if you want your client-side script to have knowledge about the particular controls it is required to modify?

The first step is to ensure that the page on which the custom field will be rendered references the jQuery library. My approach is to add script elements to the RenderingTemplate in the custom field ASCX user control (which is deployed to the CONTROLTEMPLATES 12 hive folder), and to deploy the jQuery library to the LAYOUTS 12 hive folder.

Then, to enable the code in the custom field to set parameters in the client-side script (for example, to set the name of another field in the new/edit form that the script is to interact with), I added in the RenderingTemplate another script tag that contains an asp:Literal server control. Custom field code in the BaseFieldControl subclass can then output script into this literal control.

I created a custom field editor which derives the information to be rendered into that Literal control, and save this information in a custom property of my custom field. The technique for storing custom properties is explained well by Anton Myslevich in this forum thread (thanks, Anton!), particularly the difficulty in saving properties for a new instance of a custom field.

To summarise, the SharePoint list administrator adds a new field of type "MyCustomjQueryField" to a list and applies some custom configuration settings in the "Create New Field" form. These settings are processed and stored as custom properties of the custom field instance. When a list item is create or edited by a list user, the new or edit form is displayed, and the custom field uses its saved custom properties to render JavaScript in a hidden table row in that form. The JavaScript then uses the power of jQuery to interact with other fields in that form.

Displaying a Message During the AJAX Call

One small use of jQuery was to show a message in the new/edit form whilst a web service call initiated by the custom field was occuring. This is important given the asynchronous nature of the call and the fact that it is possible for the call to take a noticeable time to complete.

This was achieved using the 'after()' jQuery manipulation method to add a span directly after the HTML element in the form that was being modified by the web service call. Before the jQuery AJAX call is made, I add this span, and then remove the span in the event handlers for the error and success events triggered on completion of the AJAX call.

One small but pleasing touch was to fade out the message using the 'fadeOut()' jQuery method. Unnecessary perhaps, but less jarring to the eye than the text just disappearing instantly.

No comments: