Archive for September, 2010
Example of using the SPServices Search web service
Instead of CAML you can also use a search query by using SQL or keyword syntax to search the SharePoint environment client-side by using the Search web service. The SPServices library supports the Query operation to do this.
Hereby I show you a few examples of how to use it.
First let’s start building the query. The query is based on the Microsoft.Search.Query schema, which can be found here: http://msdn.microsoft.com/en-us/library/ms563775.aspx
A query using keyword syntax:
var queryText = "<QueryPacket xmlns='urn:Microsoft.Search.Query' Revision='1000'>" queryText += "<Query>" queryText += "<Context>" queryText += "<QueryText language='en-US' type='STRING'>" queryText += "Estonia"; queryText += "</QueryText>" queryText += "</Context>" queryText += "</Query>" queryText += "</QueryPacket>";
To fire this query by the Query operation of the Search web service via SPServices the following code can be used:
var title, url = "";
$().SPServices({
operation: "Query",
queryXml: queryText,
completefunc: function(xData, Status) {
$(xData.responseXML).find("QueryResult").each(function() {
//let's see what the response looks like
$("#result").text($(this).text());
});
}
});
#results is a div element with the id results to show the response of the query web service. The response format returned by the query web service for the Query operation is described by the Microsoft.Search.Response schema (http://msdn.microsoft.com/en-us/library/ms578335.aspx)
The result of running the above example:
<ResponsePacket xmlns="urn:Microsoft.Search.Response"> <Response> <Range> <StartAt>1</StartAt> <Count>1</Count> <TotalAvailable>1</TotalAvailable> <Results> <Document relevance="428" xmlns="urn:Microsoft.Search.Response.Document"> <Title>Estonia</Title> <Action> <LinkUrl size="0" fileExt="aspx">http://your_url/Lists/Country/DispForm.aspx?ID=24</LinkUrl> </Action> <Description /> <Date>2010-04-08T13:45:47+02:00</Date> </Document> </Results> </Range> <Status>SUCCESS</Status> </Response> </ResponsePacket>
One result is returned here to show a simple and small piece of xml. The results element contains the actual result of the query, the document element contains a single content item in the search results.
A query using SQL syntax:
var queryText = "<QueryPacket xmlns='urn:Microsoft.Search.Query' Revision='1000'>"
queryText += "<Query>"
queryText += "<Context>"
queryText += "<QueryText language='en-US' type='MSSQLFT'>"
queryText += "SELECT Title, Rank, Size, Description, Write, Path FROM portal..scope() WHERE CONTAINS ('Estonia') ORDER BY \"Rank\" DESC"
queryText += "</QueryText>"
queryText += "</Context>"
queryText += "</Query>"
queryText += "</QueryPacket>";
And the result:
<ResponsePacket xmlns="urn:Microsoft.Search.Response"> <Response> <Range> <StartAt>1</StartAt> <Count>1</Count> <TotalAvailable>1</TotalAvailable> <Results> <Document xmlns="urn:Microsoft.Search.Response.Document"> <Action> <LinkUrl fileExt="aspx">http://your_url/Lists/Country/DispForm.aspx?ID=24</LinkUrl> </Action> <Properties mlns="urn:Microsoft.Search.Response.Document.Document"> <Property> <Name>TITLE</Name> <Type>String</Type> <Value>Estonia</Value> </Property> <Property> <Name>RANK</Name> <Type>Int64</Type> <Value>1000</Value> </Property> <Property> <Name>SIZE</Name> <Type>Int64</Type> <Value>0</Value> </Property> <Property> <Name>WRITE</Name> <Type>DateTime</Type> <Value>2010-04-08T13:45:47+02:00</Value> </Property> <Property> <Name>PATH</Name> <Type>String</Type> Value>http://your_url/Lists/Country/DispForm.aspx?ID=24</Value> </Property> </Properties> </Document> </Results> </Range> <Status>SUCCESS</Status> </Response> </ResponsePacket>
The results of the keyword and SQL syntax are slightly different. Keep this in mind while traversing the xml and getting the title for instance.
By using the SQL syntax and getting the title in the resulting xml, the Property element is involved:
$().SPServices({
operation: "Query",
queryXml: queryText,
completefunc: function(xData, Status) {
$(xData.responseXML).find("QueryResult").each(function() {
var x = $("<xml>" + $(this).text() + "</xml>");
//let's see what the response looks like
//$("#result").text($(this).text());
//traverse the xml to get the items
x.find("Document").each(function() {
//when using SQL syntax
url = $("Action>LinkUrl", $(this)).text();
$(this).find("Property").each(function() {
if ($("Name", $(this)).text() == "TITLE") {
title = $("Value", $(this)).text();
}
});
//end SQL syntax
$("#result").text("title: " + title + " - LinkUrl: " + url);
});
});
}
});
By using the keyword syntax and getting the title, it’s just a direct child element of the Document element and this code can be used:
$().SPServices({
operation: "Query",
queryXml: queryText,
completefunc: function(xData, Status) {
$(xData.responseXML).find("QueryResult").each(function() {
var x = $("<xml>" + $(this).text() + "</xml>");
//let's see what the response looks like
//$("#result").text($(this).text());
//traverse the xml to get the items
x.find("Document").each(function() {
url = $("Action>LinkUrl", $(this)).text();
//when using keyword syntax
title = $("Title", $(this)).text();
//end keyword syntax
$("#result").text("title: " + title + " - LinkUrl: " + url);
});
});
}
});
The examples described here give just one result for demonstration purposes. This can be seen at the elements count and totalavailable in the result xml. Count is the actual number of items returned, while totalavailable is the total number of results returned by the query web service. When getting real life results please mind the number of items returned by default is 10. Of course the query can be adjusted with a custom count:
var queryText = "<QueryPacket xmlns='urn:Microsoft.Search.Query' Revision='1000'>" queryText += "<Query>" queryText += "<Range><Count>50</Count></Range>"; queryText += "<Context>" queryText += "<QueryText language='en-US' type='STRING'>" queryText += "Estonia"; queryText += "</QueryText>" queryText += "</Context>" queryText += "</Query>" queryText += "</QueryPacket>";
To fully optimize the query to your needs please check out the Microsoft.Search.Query schema for a lot of useful options.
Simple Alert Me option on a SharePoint page with SPServices
On SharePoint lists you can receive email notifications when items change in a list, the ‘Alert me’ function in the Actions menu of a list.

In some occasions there are multiple lists where the data in it is interesting to monitor. For example values of currencies or commodities. When a webpart is used to display values of these lists to users it can be difficult for users to set the email notifications on one or more of these lists, because the user doesn’t (have to) know which lists are involved.To make it all a bit user friendly I’m going to give the user the possibility to easily add an email notification at the same page the webpart is displayed. The user can stay on one page to analyze some data and create a notification for the lists used (the source data lists) in the webpart.
The webpart (not specified further here) to analyze some data uses a subset of all the lists available at the SharePoint site. The lists used are listed in another list, from now on called BaseList. So the BaseList contains all the lists (static name) used as source data.
Content editors can easily add other lists with data to the SharePoint site for analyzing purposes. To use these lists for analyzing purposes in the webpart they can add (or remove) that list to the BaseList. The webpart uses all the lists specified in BaseList and the users can set notifications to these lists.
For displaying all the possible email notifications to set on the page, SPServices comes to the rescue.
Because of the BaseList it is easy to determine which source data lists are involved. To set an email alert always the same default SharePoint page from the _layouts folder is used: SubNew.aspx with the listguid as parameter. If these two are combined, the solution is already there.
First a function is created to retrieve all the lists from the BaseList:
function GetAvailableLists(listName) {
counter = 0;
$().SPServices({
operation: "GetListItems",
listName: listName,
async: false,
CAMLViewFields: '<ViewFields><FieldRef/><FieldRef/></ViewFields>',
completefunc: function(xData, Status) {
$(xData.responseXML).find("[nodeName= z:row]").each(function() {
GetListId($(this).attr('ows_NameOfList'), $(this).attr('ows_DisplayNameOfList'));
counter += 1;
});
}
});
}
The ViewFields contains two columns of the BaseList, one for the static name of the list and one with a self made up display name. The display name will be used as text of the link generated below, the static name for retrieving the guid of the list.
In the code above the function GetListId() is used:
function GetListId(listName, displayName) {
var id = "";
$().SPServices({
operation: "GetList",
listName: listName,
async: false,
completefunc: function(xData, Status) {
id = $(xData.responseXML).find("List").attr("ID");
if (id != null) {
items[counter] = "<a href='/_layouts/SubNew.aspx?List=" + id + "&Source=" + returnToPage + "'>" + displayName + "</a>";
}
}
});
}
This piece of code gets the guid of the list and formats the right url for the notification. The Source parameter here is set to a returnpage. It is convenient for the user to be redirected to page he was coming from otherwise he will be redirected to the AllItems.aspx page from the list where the notification has been set. The formatted url is stored in an array, because I have another function for displaying it nicely at the page, that I’m going to leave to your imagination.
Copy all the code in a Content Editor webpart and you’re done.
The result on the page is dependent on how you format it, but practically no more than a bunch of links, e.g.:
With the link set to:
http://<your site>/_layouts/SubNew.aspx?List={1FAFC5F9-F8D8-4CB6-852E-5AD4DB12CB04}&Source=Default.aspx
A better user experience with the dialog framework and notifications
Today I am playing around with the dialog framework and simple ribbon buttons. I want the user to select one or more items from a list and update the Status field for all the items selected. The user can edit multiple items in datasheet view of course, but I’m making it just a little friendlier to the user.
I give myself two challenges for today:
Add a button to the ribbon, enabling it when one or more items in the list are selected and update the Status field to ‘Completed’ of the selected items. This will be described at the paragraph ‘Just the button’ below.
For more flexibility I will extend the above solution by a modal dialog where the user can choose a value for the Status column instead of setting the value to ‘Completed’ (and is not mentioned to the user anywhere), update the selected items and give the user a notification message if the update was successful and mentioning the Status value from the control on the modal dialog. This will be described at the paragraph ‘Modal dialog’ below.
The last option will give the user a better experience and will be a lot more flexible, because I’m not setting the value of the Status field in the code, but let the user choose from a predefined set of values.
Not really challenges, but I just want to point out a few things which are maybe interested to you. I’m not going to explain the basics of the ribbon or the dialog framework, because there are a lot of excellent posts out there.
Just the button
Add a button to the ribbon: please check out the cmdui.xml file located the SharePoint root folder, template\global\xml. Here you find a lot of definitions and examples you can use yourself and really helpful by positioning the controls on the ribbon.
To just enable a button when one or more items in a list are selected is quite easy:
when defining a CustomAction with for example a button, you also define a CommandUIHandler. One of the attributes is EnabledScript:
EnabledScript="javascript: function enableMarkAsCompletedButton(){
var items = SP.ListOperation.Selection.getSelectedItems();
return (items.length >= 1);
}
enableMarkAsCompletedButton();”
Check the above code to enable the button (in this case) only when one or more items are selected. Here the client object model for ECMA script is used to get the selected items.
Another attribute is CommandAction, the real action to occur when the button in the ribbon is clicked. The code used here:
CommandAction="javascript:
var context = SP.ClientContext.get_current();
var currentList = context.get_web().get_lists().getById(SP.ListOperation.Selection.getSelectedList());
var items = SP.ListOperation.Selection.getSelectedItems();
var singleItem;
for (var i in items) {
singleItem = currentList.getItemById(items[i].id);
singleItem.set_item('Status', 'Completed');
singleItem.update();
}
//actually submit
context.executeQueryAsync(OnSuccess, OnError);
function OnSuccess() {
window.location.href = window.location.href;
}
function OnError(sender, args) {
alert('Error' + args.get_message());
} "
First grab the context and the list we’re at. The getSelectedList() is the input of the getById() function. The result is the actual list where later the getItemById() function can be used on.
Also check the for-loop. You can’t use items[i].id directly in the getItemById() function on the list, but you have to grab the id of the single item and use this as the input parameter. Don’t use the context.load() function, just execute the query asynchronously. The OnSuccess() function refreshes the page so the adjusted value can be seen and an alert is displayed when an error occurs.
Modal dialog
By using a modal dialog and give the result back to the user the user experience will be much better. I don’t use a predefined value in the code but let the user choose which Status to set on all the selected items at once. Because I’m using a dialog some additional text to explain the function and result better will be convenient for the user.
For displaying a modal dialog the function SP.UI.ModalDialog.showModalDialog(options) will be used. The options I’m going to use here are the url, width, height and the most important to explain here the dialogReturnValueCallback.
The url is a custom page which will be opened. At the dialogReturnValueCallback a callback function will be specified, this means what is going to happen when the user closes the dialog. At our case the selected items in the list will be updated with the new status.
A lot of the above code can be reused at this scenario:
enabling the button when one or more list items are selected will not change at all.
updating the list items will occur at a different moment, because we’re going to display a dialog first to let the user choose the Status for the selected items.
First let’s look at the showModalDialog(options) and the page that will be opened at the url. I put the page at a subdirectory of the _layouts folder, so referencing is easy.
In the page itself I put a dropdown control with some status values and a button to actually set the status. For better user experience I will list the selected items at the model dialog, so the user is still aware of what items are going to change. To list the items selected I will add the parameters listguid and the id’s of the items selected to the url at the options for the showModalDialog function:
var options = {
url: '/_layouts/ITIdea.DialogFramework/PageSetStatus.aspx?listguid=' + SP.ListOperation.Selection.getSelectedList() + '&items=' + selectedItems,
height : 600,
width : 500,
dialogReturnValueCallback : CloseCallback};
SP.UI.ModalDialog.showModalDialog(options);
And at the Page_Load function of the page I’m getting the listguid and selected items and display it in a simple label control on the page (please do not use this code as production code!):
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString["listguid"] != null && Request.QueryString["items"] != null)
{
string list = Request.QueryString["listguid"].Substring(1, Request.QueryString["listguid"].Length - 2);
Guid listGuid = new Guid(list);
List<string> selectedItems = new List<string>();
selectedItems.AddRange(Request.QueryString["items"].Split(','));
SPList selectedList = SPContext.Current.Web.Lists[listGuid];
string result = "Selected items: <br />";
foreach (string item in selectedItems)
{
result += selectedList.GetItemById(int.Parse(item)).Title + "<br />";
}
selectedItemsText.InnerHtml = result;
}
}
And this is how is looks like in its simplest form:

After the ‘Set’ button is selected the list items will be updated and for better user experience the user will be notified by a yellow notification on the right of the screen to what status the selected items are set. All this can be done at the function defined at dialogReturnValueCallback in the options of the showModalDialog, CloseCallback:
function CloseCallback(result, target) {
if(result == SP.UI.DialogResult.OK){
SP.UI.Notify.addNotification('Status value is set to ' + target, true);
//set the status of all the selected items to the text
AdjustFields(target);
}
if(result == SP.UI.DialogResult.Cancel){
SP.UI.Notify.addNotification('Result is Cancel');
}
}
function AdjustFields(newValue){
var context = SP.ClientContext.get_current();
var currentList = context.get_web().get_lists().getById(SP.ListOperation.Selection.getSelectedList());
var items = SP.ListOperation.Selection.getSelectedItems();
var singleItem;
for (var i in items) {
singleItem = currentList.getItemById(items[i].id);
singleItem.set_item('Status', newValue);
singleItem.update();
}
//actually submit
context.executeQueryAsync(OnSuccess, OnError);
}
function OnSuccess() {
setTimeout(window.location.href = window.location.href, 3000);
}
function OnError(sender, args) {
alert('Error' + args.get_message());
}
The code for actually update the selected list items is moved to the AdjustFields function with newValue as input parameter and executed at the callback function of the dialog. This newValue is the value selected in the dropdown by the user at the modal dialog. How did we get that value over here?
Here another function of the SP.UI.ModalDialog comes in: commonModalDialogClose().
With this function you can set your own return value which will be used at the callback function of the showModalDialog(). Real nice function!!
To set a custom return value for the callback function, I use the commonModalDialogClose at the click eventhandler for the Set button at the page which is displayed as the modal dialog:
function SetNewStatus_Click() {
var resultText = document.getElementById('StatusChoices').value;
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK, resultText);
}
In the above code the element ‘StatusChoices’ is the id of the dropdown control with the different status values. With the commonModalDialogClose() the dialog result is set to OK and the result value is set to the selected value in the dropdownbox.
By setting the result to OK, the code in the CloseCallback() function will execute the code in the first if-statement. Here the message for the notification is set and the return value (target parameter, which was set at SetNewStatus_Click() ) is added to the notification message.
After explaining this simple example you’re getting the idea of a better user experience with modal dialogs and notification messages. Inform the user as much as you can, the options are given to you by SharePoint and who are we not using them…
Enable ECMA COM Intellisense Visual Studio 2010
While investigating and playing with the dialog framework of SharePoint 2010 I really missed some intellisense of the client object model for the javascript(ECMA) code. It seems real easy to enable intellisense and saves a lot of time!
First create a js file in Visual Studio 2010.
Add the line below as the first line:
/// <reference name="MicrosoftAjax.js" />
This line of script has to be referenced as the first line, because it has all the default methods for Sys.* available (this js is a Visual Studio file). Also the declaration of the js file which uses the intellisense is dependent of the order in which they appear in the js file. Some of the SP objects depend on this file.
After the base reference for Visual Studio add the SharePoint ECMA script files:
/// <reference path=”file://C:/Program Files/Common Files/Microsoft Shared/Web Server Extensions/14/TEMPLATE/LAYOUTS/SP.core.debug.js” />
/// <reference path=”file://C:/Program Files/Common Files/Microsoft Shared/Web Server Extensions/14/TEMPLATE/LAYOUTS/SP.debug.js” />
These two files are the primary files needed for the intellisense.
After these references you can add every debug.js file available in the SharePoint root(14) layouts folder you want.
For example developing the dialog framework add the following reference:
/// <reference path=”file://C:/Program Files/Common Files/Microsoft Shared/Web Server Extensions/14/TEMPLATE/LAYOUTS/SP.UI.Dialog.debug.js” />
When you add a reference and the intellisense is not updated with the last reference, press Ctrl-Shift-J and you will see the statusbar indicating the intellisense is updating:
![]()
Please remove the references to the debug.js files while deploying to a production environment.
More options: http://msdn.microsoft.com/en-us/library/ff798328.aspx
Permormance issue GetItemById
Be careful with the use of GetItemById(), there are two options to use it:
SPList.Items.GetItemById()
SPList.GetItemById()
The difference between the two is that the SPList.Items.GetItemById() loads every item into memory and then filters the set. Trust me: this can cause severe perfomance issues when using this on lists with a large number of items.
SPList.GetItemById() doesn’t do this and is way faster because of this. Be warned!
jQuery SPServices get list guid
A very easy way to retrieve the guid of a list with SPServices:
<script type="text/javascript" src="../ICTLibrary/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="../ICTLibrary/jquery.SPServices-0.5.4.min.js"></script>
<script type="text/javascript">
$("document").ready(function() {
function GetListId(listName) {
var id = "";
$().SPServices({
operation: "GetList",
listName: listName,
async: false,
completefunc: function (xData, Status) {
id = $(xData.responseXML).find("List").attr("ID");
}
});
return id;
}
var listid = GetListId("Plastic");
if(listid!=null)
{
$("#listid").append(listid);
}
else
{
$("#listid").append("list not found");
}
});
</script>
<div id="listid" >Plastic list guid: </div>

