On my personal SharePoint site I use the SharePoint Links type lists a huge amount, I have at least 20 of these and I like to flick between them a lot, having the links to hand is a great productivity booster.
I find the standard navigation just too slow and although the double-click minimize/restore Web Part helps what I really wanted was a windows application usability for these lists.
This is a perfect job for client-side JavaScript making SOAP calls to the SharePoint WebServices using DHTML to display the items. This kind of code now has the nifty name of AJAX although this is really AJAX-lite as the size of our framework is tiny and doesn’t need to handle complex object serialization/deserialization or data binding.
The goal is to have a WebPart that lists the Links based lists (must be an easier way to say that) and with a click display the items on the list, I also wanted to have an easy way to add items into the list. All code would be client-side javascript and also needed to work in Mozilla based browsers such as FireFox as I also use that a lot. Once the initial page has been rendered as normal by SharePoint there are no other postbacks or page refreshes needed so response times are very fast.
The Javascript will be initially be hosted in a Content Editor Web Part but I plan to create a server side WebPart also. Here’s a screen shot.
List of Lists
Add a new Item

SharePoint already does some AJAX already, albeit in a limited fashion, to handle getting and setting Web Part properties while editing the Properties of Web Parts. It posts to the WebPartPages.asmx SOAP service using the SaveWebPart and GetWebPart SOAP methods. Note the built-in SharePoint SOAP calls are only made if the browser is IE 5 and up. This and the fact that the library calls are hard-coded to use the WebPartPages web service only meant I had to create my own routines.
Soap requests by hand
Ok down to the nitty-gritty.
I’m going to assume you already have some understanding of what SOAP is but basically it is the method of sending an XML formatted request to a URL via HTTP and getting back a XML formatted response.
The first thing our Web Part needs is the list of Links type lists on the SharePoint site we are on.
To do this we will call the GetListCollection method of the Lists.ASMX web Service.
If you add /_vti_bin/lists.asmx page to your site URL you will see the methods this service exposes. Click the GetListCollection method to see the format of the SOAP request it expects.
The function GetLinksList populates the list of links and is the entry point into our code. We hook into the windows load event like this:
if (window.addEventListener)
window.addEventListener('load', _WPQ_AjaxObject.GetLinksList, false);
else
window.attachEvent("onload",_WPQ_AjaxObject.GetLinksList);
Note the use of the _WPQ_ token, this is replaced by our Web Part ID by the CEWP at runtime so avoiding duplicate global variables when there are two instances of the same Web Part on a page.
So we send a POST request to the URL /_vti_bin/Lists.asmx?op=GetListCollection and make sure we have a SOAPAction header set to the correct operation which is http://schemas.microsoft.com/sharepoint/soap/GetListCollection.
This will give use a list of all lists which we can filter for the Links’s type.
The body of the request will look like this:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body>
<GetListCollection xmlns="http://schemas.microsoft.com/sharepoint/soap/"/>
</soap:Body>
</soap:Envelope>
This is a very simple request string and notice the majority of the text is the boilerplate SOAP XML envelope that will never change, so in the code I’ve created vars that contain this text called SoapPrefix and SoapPostFix
To submit the request we create a XMLHttpRequest object and use its send method asynchronously, the function that calls the List Web Service looks like this
function ajaxsp_GetLinksList()
{
var xmlrequest;
xmlrequest = aSoapPrefix+ '<GetListCollection xmlns="http://schemas.microsoft.com/sharepoint/soap/"/>'
xmlrequest += SoapPostfix;
if (!xmlhttpLists) xmlhttpLists= GetHTTPObject();
xmlhttpLists.open("POST, "_vti_bin/Lists.asmx?op=GetListCollection",true);
xmlhttpLists.setRequestHeader("Content-Type","text/xml; charset=utf-8");
xmlhttpLists.setRequestHeader("SOAPAction","http://schemas.microsoft.com/sharepoint/soap/GetListCollection");
xmlhttpLists.setRequestHeader("Content-Length", xmlrequest.length);
// set the callback event
xmlhttpLists.onreadystatechange=ajaxsp_GetLinksListEvent;
// Send the request
xmlhttpLists.send(xmlrequest);
return true;
}
Two important functions are GetHTTPObject which returns the HttpRequest object for both IE and Mozilla based browsers and the ajaxsp_GetLinksListEvent which does the heavy lifting of processing the returned XML
GetHTTPObject needs to create different objects for IE and Mozilla because Mozilla has a built-in native Javascript object called XMLHttpRequest whereas IE uses the ActiveX XMLHTTP object contained in MSXML libraries, there a quite a few versions of this library and the ProgID changes with each one but I just use either Msxml2.XMLHTTP of Microsoft.XMLHTTP which should cover most modern machines with IE5.0 and up, interestingly IE 7 has now gained the native XMLHttpRequest object.
Heres a snippet of the returned XML.
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body><GetListCollectionResponse xmlns="http://schemas.microsoft.com/sharepoint/soap/">
<GetListCollectionResult>
<Lists>
<List DocTemplateUrl="" DefaultViewUrl="/Lists/Company Links/AllItems.aspx" ID="{60E01147-6A7A-47F0-8CA1-4D88426280DE}" Title="1 Company Links" Description="" ImageUrl="/_layouts/images/itlink.gif" Name="{60E01147-6A7A-47F0-8CA1-4D88426280DE}" BaseType="0" ServerTemplate="103" Created="20050225 11:43:06" Modified="20060222 09:58:24" LastDeleted="20060220 17:42:54" Version="1" Direction="none" ThumbnailSize="" WebImageWidth="" WebImageHeight="" Flags="4105" ItemCount="16" AnonymousPermMask="" RootFolder="" ReadSecurity="1" WriteSecurity="1" Author="3" EventSinkAssembly="" EventSinkClass="" EventSinkData="" EmailInsertsFolder="" AllowDeletion="True" AllowMultiResponses="False" EnableAttachments="False" EnableModeration="False" EnableVersioning="False" Hidden="False" MultipleDataList="False" Ordered="True" ShowUser="True" />
<List DocTemplateUrl="" DefaultViewUrl="/Lists/Links/AllItems.aspx" ID="{233585BA-5972-40BB-85C8-67F793F22F67}" Title="2 Links" Description="Use the Links list for links to Web pages that your team members will find interesting or useful." ImageUrl="/_layouts/images/itlink.gif" Name="{233585BA-5972-40BB-85C8-67F793F22F67}" BaseType="0" ServerTemplate="103" Created="20041008 14:10:07" Modified="20060224 10:43:07" LastDeleted="20050302 08:40:12" Version="1" Direction="none" ThumbnailSize="" WebImageWidth="" WebImageHeight="" Flags="4105" ItemCount="26" AnonymousPermMask="" RootFolder="" ReadSecurity="1" WriteSecurity="1" Author="3" EventSinkAssembly="" EventSinkClass="" EventSinkData="" EmailInsertsFolder="" AllowDeletion="True" AllowMultiResponses="False" EnableAttachments="False" EnableModeration="False" EnableVersioning="False" Hidden="False" MultipleDataList="False" Ordered="True" ShowUser="True" />
As you can see a large amount of information is returned for each list but I’m most interested in four attributes of each list:
Name –List Name for display
ServerTemplate – for filtering
DefaultViewURL – to allow jumping to the standard SharePoint links page
Hidden - for hiding hidden lists.
The ServerTemplate is used to filter out only those lists that are Links based list which have a list template of 103. I use the constant LISTTEMPLATE_LINKS which is defined in ows.js.
The routines for parsing this XML into DOM nodes brings out the second major difference between IE and Mozilla : IE uses the MSXML ActiveX objects whereas Mozilla has the XML parsing javascript objects built-in.
I’ve encapsulated the conversion of the response XML into a set of DOM nodes into the GetSoapResponseItems routine
// Cross Browser helper to filter the XML results
// Returns array of Node objects
function ajaxsp_GetSoapResponseItems(SoapResponseXML, XPathFilter, NSResolver)
{
var m_Items=[];
// Mozilla
if (window.addEventListener)
{
var aItems = xmlhttpLists.responseXML.evaluate(XPathFilter, SoapResponseXML, NSResolver, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null)
for( var i = 0; i < aItems.snapshotLength; i++){m_Items[i] = aItems.snapshotItem(i);}
}
else
{ // IE
var xmlDom=new ActiveXObject("MSXML2.DOMDocument.3.0");
xmlDom.async=false;
xmlDom.loadXML(SoapResponseXML.xml);
m_Items=xmlDom.selectNodes(XPathFilter.replace("sp:",""));
}
return m_Items;
}
In IE you create a MSXML.DomDocument ActiveX object and use its LoadXML method to load the XML and use selectNodes with an XPath expression to get back the list of items
Mozilla has support for a lot of the DOM Level 3 XPath (http://www.w3.org/TR/DOM-Level-3-XPath/xpath.html) which allows XPath expression to be run against the XML data. The responseXML property is actually an object that has parsed the XML but unfortunately it doesn’t have support for selectNodes so you have to use the evaluate function to get a XpathResult and with that you can add the individual Dom nodes to an array.
One wrinkle with Mozilla is that’s its very picky about NameSpaces so you must specifiy a prefix in your XPath filter for default namespaces and also you need a routine that converts the prefix to the full Namespace, there are a couple of ways of doing this but a simple function returning a string is the easiest.
function moz_NSResolver1(NSPrefix)
{
switch(NSPrefix)
{
case "soap" : return "http://schemas.xmlsoap.org/soap/envelope/"; break;
default : return "http://schemas.microsoft.com/sharepoint/soap/";
}
}
As this function needs to vary depending on the XML I pass this in as function pointer in parameter NSResolver.
IE does some guessing for you so we can strip the prefix from the XPath filter.
Now once we have the Links Lists I create a set of ListItems (LI) in an Unordered List (UL) and display them by setting the innerHTML of a DIV element.
Whew, thats enough for one entry, In part 2 I’ll delve into displaying the actual links and creating a form for adding a new item using the client-side OWS Field objects and post the DWP file that contains all the code and which can be imported into your Web Part page.