Sunday, April 02, 2006
« Cross-Browser AJAX for SharePoint Lists ... | Main | Client Side: Who am I? »

In part 1 we have got to the point where we have called the SharePoint lists.asmx Web Service and retrieved the list of all Lists on our SharePoint site.
We now need to filter down to only those lists that are based on the links list template, this is template type 103, we can use an Xpath expression to filter the items.

// Filter for the Links lists items
links_lists=ajaxsp_GetSoapResponseItems(xmlhttpLists.responseXML, "//sp:List[@ServerTemplate='" + ListTemplate + "']", moz_NSResolver1 );

We loop through the list items and use the getAttribute of the XML Dom node to retrieve the fields we are interested in and concatenate a string of <LI> items which we then set to the innerHTML property of a DIV element.

Each list item on the left is a hyperlink that calls the javascript function GetLinkItems when clicked.
This function is passed three parameters - the list Guid, list Title and the Default View URL which normally is the full list of links.

function GetLinkItems(ListGuid, ListName, ListDefaultView)


To get the list items we need to call the GetListItems method and pass it the listName parameter.

// Create SOAP Request
xmlrequest = SoapPrefix + '<GetListItems xmlns="http://schemas.microsoft.com/sharepoint/soap/">'
xmlrequest = xmlrequest + '<listName>' + ListGuid + '</listName></GetListItems>' + SoapPostfix;

To send the SOAP request we do the same as before only this time we set the GetListItems SOAP method

xmlhttpItems.open("POST", "_vti_bin/Lists.asmx?op=GetListItems ",true); xmlhttpItems.setRequestHeader("Content-Type","text/xml; charset=utf-8"); xmlhttpItems.setRequestHeader("SOAPAction","http://schemas.microsoft.com/sharepoint/soap/GetListItems ");
// Set event handler
xmlhttpItems.onreadystatechange=ajaxsp_GetLinkItemsEvent;
// Post request
xmlhttpItems.send(xmlrequest);

Our GetLinkItemsEvent parses the XML and formats the data into a TABLE element with the ms-summarycustombody style to match the theme of the SharePoint site.
Each hyperlink has the target=”_blank” attribute which causes the links to open in a new window, my preferred method of opening links. This can easily be changed.


Creating a new Item Form

Now we have displayed our list of links we need to look at adding a new item.
In the Web Part after the script blocks I have some HTML that contains a DIV element. The DIV element has a style that sets its position to be absolute and hidden.
Inside the DIV I’ve create a HTML table that sets the layout of the AddNew form.
To render the URL editing and Notes fields I use the built-in functions provided in the SharePoint javascript file ows.js to handle input fields on SharePoint forms.
The complete list of fields type that can be used are:

DateField
URLField
NumberField
BooleanField
NoteField
RichTextField
TextField
FileNameField
GridChoiceField
ChoiceField

I only need to use the URLField and NoteField type.


These functions are called in javascript like this
var fld = new URLField(frm,"URL","URL", "","");
fld.fRequired = true;
fld.IMEMode="";fld.BuildUI();

The URLField function takes parameters of a OWSForm, Internal Field Name, Display Name, Default URL Value , Default Description.
BuildUI takes care of creating the input HTML which is great as it automatically creates two input fields, one for the URL and one for the description.

I create a NoteField object like this.

fld = new NoteField(frm,"Comments","Notes","");
fld.stNumLines = "6";
fld.IMEMode="";
fld.BuildUI();

The NoteField functions parameters are a OWSForm, Internal Field Name, Display Name, Default Note Field Value


Heres the function prototype for creating a OWSForm object:

function OWSForm(stName, fUseDHTMLOverride, stPagePath)

Creating the OWSForm is tricky in that it’s easy to create the OWSForm object in itself but it expects the name of the onpage form used in the WebPart page postbacks, that’s fine but it overwrites the onsubmit function which causes problems for any other component like the Web Part settings toolbar that need to post to the server. The way around this is to pass it a dummy name and then after the call set the Form name to the genuine article.
The second parameter is fUseDHTMLOverride which is used to force the use of DHTML when rendering the controls.
stPagePath is used to locate any extra files needed such as the datepicker’s template htm page.

Heres how its called in code

// Pass a dummy form name so it does not overwrite the Submit event
var _WPQ_frm= new OWSForm("DummyName" , true, "_layouts/");
// Now assign the proper form name it as it’s needed for the fields to locate their values
_WPQ_frm.stName=MSOWebPartPageFormName;

We use the global variable MSOWebPartPageFormName here which is defined in ows.js and available on all WebPartPages and gives the name of the FORM element used for postback. Note we don’t postback ourselves but the OWS Field elements think that they might.

I’ve laid out the new item form with the Javascript to create the edit fields embedded in a HTML table. This table is wrapped in a DIV which is initially hidden. The code to show and center the DIV element is Javascript 101 so I won’t go into details but check the function ajaxsp_DisplayNewForm if you’re interested.

I want to set focus to the Http edit field so we need to a reference to the Edit fields.
We can use getElementById for this but we need to know the name of the field on the form.
The key to this is to understand how the OWS form elements name themselves.

Fields are named by the internal function FrmStFieldNameFactory which does this:
return "OWS:" + name + ":" + stPart;
This concatenates OWS with the name of the field and the subfield name.

The URL field type is composed of two sub fields named URL and Desc. In this case we’re referencing the URL field and the URL subpart of that field.

So to reference the URL sub part of the URL field we can use this code.

var fldURL=document.getElementById("OWS:URL:URL");
if (fldURL) fldURL.focus();

 

Adding a new record via SOAP services

Now that we can get the URL, Description and Notes field values we use the UpdateListItems method of the Lists.asmx web service to add the new record.
This method takes a CAML string to do adds, updates and deletes.
This is an example CAML batch string we send:

<Batch>
<Method ID='1' Cmd='New'>
<Field Name='URL'>http/www.google.com, Description here - note comma and space</Field>
<Field Name='Comments'>My Comment String</Field>
<Method>
</Batch>

The ajaxsp_AddListItem routine assembles this string, places it inside the UpdateListItems SOAP string and sends it to the web service. 
The ajaxsp_AddListItemEvent handles the returned SOAP string which may include a faultstring node if the SOAP call fails or an ErrorText node if the new record fails to add in SharePoint. Once the insert succeeds we hide the new item form and refresh the list.

Thats almost it, there is some extra code where I store the last displayed list in a cookie so if the page refreshes I can display the list items again. This cookie is designed to only last for the browser session.


 

Summary

This has been a deep dive into calling the SharePoint Web Services from client side javascript but the actual methods involved are pretty basic and simple to use, most of the complications and extra code come from handling non IE browsers.

Some of the other ways that Web Services could be used include adding field by field server-side validation, filling comboboxes from SQL Server tables, getting unread email counts information from Exchange via WebDav.

Feel free to download the DWP file and browse the code for yourselves.

LinksLists.dwp (16.2 KB)