Print This Post

A javascript API for the SharePoint and Office Live Web Services

Quite a while ago I published a small article on how to call a SharePoint web service via javascript. Back then (and now too) I was doing a lot of work with Office Live and this was one of the only ways to really interact with the system since running server side code in Office Live is prohibited (with good reason).

That article gets quite a lot of hits and comments and it seems that a lot of people call the SharePoint web services from javascript routinely, although I guess this shouldn’t be a surprise in the modern world of AJAX and so on. The original article was a quick and dirty way to get at the List Data Retrieval web service of the WSS 3.0 SDK. It had some issues though. Firstly many people got confused with the way the XML packet was built up in a string- a quote missing here or there and you’re doomed to the server 500 error. The second problem was that the code only works in Internet Explorer since it relies on the XMLHttp object. This should really be made cross browser, but at the time Office Live was only available on Internet Explorer- not so now as the horizons have been expanded to include Firefox.

So I decided to redo the code and make it cross browser. I also wanted to clean up the way the XML packets were created to make it less error prone for people. Lastly, I wanted to offer some support for the processing of the result messages and examples of how to do this in a cross browser way.

To start with I wrote a little program that generated a javascript proxy for a web service. This was a fairly simple process and resulted in a large number of methods like the one below:

this.getListItems = function(listName, viewName, query, viewFields, rowLimit, queryOptions, webID)
{
    if (queryOptions == null || queryOptions == '') queryOptions = '<QueryOptions/>';

    var action = 'http://schemas.microsoft.com/sharepoint/soap/GetListItems';
    var params = [listName, viewName, query, viewFields, rowLimit, queryOptions, webID];
    var packet = '<?xml version="1.0" encoding="utf-8"?><soap:Envelope></soap:Envelope>';

    return this.core.executeRequest(this.serviceUrl, action, packet, params);
}

Each method actually has the full XML of a soap request packet specific to the web method. This is marked with placeholders for the various parameters which makes it easy to call. So I ran this against all of the SharePoint web service except the admin one.

Each SharePoint web service is represented by a single javascript class named after the service. There are 21 of these classes, each of which contains a method for each of the web methods in the service. The classes are all named after a single SharePoint web service with a JSAPI_ extension. So the class for the lists.asmx web service is in a class called JSAPI_Lists in a file called JSAPI_Lists.js. Each method within the class is named after a web method. In addition to this there is a single utility class JSAPI_Core which is in the JSAPI_Core.js file- this handles the cross browser web service calls and is required by all of the other classes.

I’ve also provided a helper class for creating request packets for the search web services. This is contained in JSAPI_Types.js. This provides a programmatic method for creating the XML request packets for searching without resorting to string building.

The intention of this library is to make it easier for solution developers to interact with the Office Live and SharePoint web service APIs and should help to make the code required easier to develop and maintain- take the following example which performs a keyword search on a SharePoint site collection:

var lists = new SPAPI_Search('');
var query = new SPAPI_QueryPacket(SPAPI_Query_Type_Keyword, 'Sharepoint', 'Title,Path,Description,Write,Rank,Size');

// Add a new sort property - sort by ID, descending, first sort property
query.addSortProperty('ID', false, 0);

// Add a new sort property - sort by Title, ascending, second sort property
query.addSortProperty('ID', true, 1);

var res = lists.query(query.getXML());

if (res.status == 200)
{
   // Get the response document
   var resultDocument = query.getResultDocument(res.responseXML);
   var status = resultDocument.getElementsByTagName('Response')[0].getElementsByTagName('Status')[0].childNodes[0].nodeValue;

   alert('The status of the search was: ' + status);

   if (status == 'SUCCESS')
   {
        var count = resultDocument.getElementsByTagName('Range')[0].getElementsByTagName('Count')[0].childNodes[0].nodeValue;
        alert(count + ' results were returned');

        var items = resultDocument.getElementsByTagName('Response')[0].getElementsByTagName('Document');

        for (var i=0; i<items.length; i++)
        {
            // Process each document result
        }
   }
  else
{
  alert('There was an error processing the search');
}

Anyway, hopefully this will be of use to people. The libraries are available in the downloads section and as usual are released open source under the Lesser GNU license. A series of examples on how to use the libraries in various scenarios will follow in my next post.

There Are 12 Responses So Far. »

  1. Hello Darren,

    I would like to preface by saying that as a newbie web developer I truly appreciate the work you have done and posted in order for the rest of us out here to learn and advance our skills.

    I came across your blog: http://darrenjohnstone.net/2008/07/22/examples-for-the-sharepoint-and-office-live-javascript-api/#topic-5 and have a few questions regarding how to use and implement these methods.

    My company just set up SharePoint to be used as our intranet platform and I have been assigned a project of creating a module that can be placed on multiple pages that will query a SharePoint list and return all of the data. I plan on doing this by creating a JavaScript function that can be called on each of those pages.

    Here is what I have thus far based off of your work ;) Thanks! -


    function GetListItems()
    {
    // Return all items in the default view of a list
    var lists = new SPAPI_Lists('rootURL')
    var items = lists.getListItems(
    'OutageAlerts', // listName
    '', // viewName
    '100', // query
    '', // viewFields
    100, // rowLimit
    'FALSE' // queryOptions
    );

    if (items.status == 200)
    {
    var rows = items.responseXML.getElementsByTagName('z:row');

    // document.getElementById('output').value = items.responseText;
    for (var i=0; i<rows.length; i++)
    {
    document.getElementById('outputdiv').innerHTML = rows;
    }
    }
    else
    {
    alert('There was an error: ' + items.statusText);
    }
    }
    _spBodyOnLoadFunctionNames.push("GetListItems");

    I am able to successfully read the list, if I set the output to show the length of the rows in the list I receive the correct number, but when I have it output the rows, it returns [object]. How can I get it to return each list item in a ? I know it’s probably something simple, I just need another set of eyes to point it out I hope.

    Thanks for your help and time,

    Matt Borsuk

  2. Hi Matt,

    I think the line

    document.getElementById('outputdiv').innerHTML = rows;

    is wrong.

    This will always emit [object] as rows is an array of objects (in itself an object).

    What you need is

    document.getElementById('outputdiv').innerHTML = rows[i].getAttribute(name);

    where name is the name of the attribute in the row (SharePoint internal column name) you wish to show.

    Good luck.

    Cheers,
    Darren

  3. Hi Darren,

    Thank you so much for getting back to me, I really appreciate your willingness to help!

    I’ve tried what you’ve suggested but the output that is being returned is null. This is what I attempted –

    document.getElementById('outputdiv').innerHTML = rows[i].getAttribute(‘Title’);

    I’m not sure if I’m calling the correct field name, are they titled something different than what is displayed in the list itself? Also, I’d rather return the entire row rather than just the column, is there a way to do that?

    Thanks again for you help!

    Best!
    Matt

  4. Hi Matt,

    The column you need will be called ows_Title. There is an example XML packet here: http://darrenjohnstone.net/wp-content/jsapi/packets/GetListItems.xml.

    If you want to get the entire row you’ll need to build it up manually from the columns. You could also consider using a client side XSL transform on the responseXML property.

    Cheers,
    Darren

  5. Hi Darren,

    I just wanted to follow up with you in regards to my inquiry. Thank you for your assistance,I was able to get everything working as I needed now I just need to style the output which shouldn’t be an issue.

    Thanks again!

    Matt

  6. Can anyone provide a demo how to put this in a content editor web part? So including a button to call the script etc.

  7. [...] usually require more programming efforts than other solutions listed here. Darren Johnstone has a very interesting post (including code) that can help you get started. Similar techniques are REST methods, and the [...]

  8. I would also like to see how to put this in a CEWP if possible

  9. Darren,
    I’m trying to get your API installed on a server and I had done it before on a long lost server. What folder on the server should I save the API support files to? I’m getting “SAPI_Lists is undefined” in a page error. I loaded the files to either of Program Files\Common Files\Microsoft Shared\web server extensions\12\ISAPI (the _vti_bin folder) or just the \bin folder.
    What is the best suggestion?

    Thanks!
    Dave

  10. Darren,
    I figured it out. I put the API .js files in the _layouts/1033 folder with the other Sharepoint .js files. I was not adding the include script to my code.

    I do appreciate the work you have done on these API calls, and they are very helpful. One thing to mention is that many of us are newbees to Sharepoint and Javascript in general. It’s helpful to have the more obvious items like where to install and the script includes in the examples.

    Thanks again for the neat API!

    Dave

  11. [...] JavaScript API may not work for anonymous users.  If you use Audience Targeting to only load for authenticated [...]

  12. [...] server-side profile store, like a SharePoint list that you connect to using JSAPI and web services, can honor the user’s preferences regardless of which device they use to [...]

Post a Response