SPServices and jQuery: pull items from multiple lists in SharePoint 2010

Let’s say you want to display all of the titles of every page library in your site collection. Using jQuery and SPServices, it’s a breeze it’s definitely possible.

What we have here are three calls of the SPServices function. First, we call the GetAllSubWebCollection operation. This will bring us all sites (webs) within a certain site collection. Once we have that, we’ll then iterate through each web to find all lists (2nd SPServices call) using the GetListCollection function. Once we have all lists, we’ll iterate through each list to look for any lists with the title “Pages”. This will give us every page library of every site in our site collection. Then we we will call our 3rd and final SPServices function, GetListItems to bring us all of the titles of all the items (in every list, in every site of this site collection). Finally, for our last act, we’ll then link each title of each item of each list of each subsite of the site collection to it’s specific URL.

But then we have to do something with that chunk of data. The last line in our code is a simple jQuery function that appends an LI with each title inside an empty UL tag with the ID of #sitelist (somewhere in your page).

Phew!

…ok, here’s the code (I just tested it, it works!):

$().SPServices({
	operation: "GetAllSubWebCollection",
	webURL: "/",
	async:false,
	completefunc: function(xData, Status) {
		$(xData.responseXML).find("Web").each(function(){
$().SPServices({
 operation: "GetListCollection",
 webURL: $(this).attr("WebFullUrl"),
 async:false,
 completefunc: function(xData, Status) {
  $(xData.responseXML).find("List").each(function(){
  //function to get all items inside every list called "Pages"
  if($(this).attr("Title") == "Pages") {
   $().SPServices({
    operation: "GetListItems",
    webURL: $(this).attr("WebFullUrl"),
    async: false,
    listName: $(this).attr("Title"),
    CAMLViewFields: "<ViewFields><FieldRef Name='EncodedAbsUrl' /><FieldRef Name='Title' /></ViewFields>",
     completefunc: function (xData, Status) {
      $(xData.responseXML).SPFilterNode("z:row").each(function() {
       var url = $(this).attr("ows_EncodedAbsUrl") + "";
       var liHtml = "<li><a href='" + url + "'>" + $(this).attr("ows_Title") + "</a></li>";
       $("#sitelist").append(liHtml);
      });
     }
    });
   }
  })
 }
});
		})
	}
})

As usual, thanks to Marc Anderson and his SPServices library

Rollup articles across a site collection (using jQuery) in SharePoint 2010

The situation: you have a great blog article you would like to rollup to a page on your site, but it is in a different site collection. What do you do? Content Query Webparts won’t do it! Well, you could create a custom webpart. You could pay a consultant and some developers to create one for you. You could find something prebuilt.

Or you could insert a few lines of jQuery and call it a day!

We’re looking to create something like this (the link would be dynamically rolled up from across a site collection):

Latest Blog Article: Rollup articles across a site collection (using jQuery) in SharePoint 2010

Skip ahead:
Download/link to SPServices
The Code
Final Result

Step 1: Download/link to SPServices

(This assumes you have already loaded jQuery itself…do that first!). SPServices is a jQuery library created by Marc D Anderson that helps you hook into SharePoints services. It does a freaking lot of stuff, but for this article we’re going to use it for rolling up some content from across a site collection. So download it from codeplex and let’s get started!

We’re going to do everything in the page using SharePoint Designer. You could load this script in your master page, or page layouts, or wherever you want. But for now, we’re going to do a one-page example. So copy this script onto your page:

<script type="text/javascript" src="/Style%20Library/scripts/jquery.SPServices-0.7.0.min.js"></script>

Step 2: the Code

First, let’s setup our placeholder for this article’s title. We will set up a span (or p, div, whatever) with and ID so we can use jQuery to find it and append the dynamically created link.

<span id="sitecollectionlink">Latest Blog Article:</span>

Next, we’ll start writing our code. I’ll break it down and then paste everything at the end. I’ve created this solution by trial and error, but there were a few discussions and examples by much smarter people on the codeplex forums that helped me with a few of the hard bits.

First let’s create a new script and call a new jQuery function on $(document).ready:

<script type="text/javascript">
$(document).ready(function() {

//code will go here

});
</script>

Let’s get into it! Our call to SPServices comes next. We’ll set the operation to “GetListItems”, set our webURL to where our blog is residing (in a separate site collection), and we pass it the list “name”. For default SharePoint blogs the list name is “Posts.” Next, we call in the fields using CAML. You’ll need two for this example, the Title field and the EncodedAbsUrl field. And finally, I’ve limited the results to just 1 because I want only one blog post showing up on my home page. Default I believe is 30 or so…

$().SPServices({
 operation: "GetListItems",
 async: false,
 webURL: "/YOUR-SITE/CHANGETHIS",
 listName: "Posts",
 CAMLViewFields: "<ViewFields><FieldRef Name='EncodedAbsUrl' /><FieldRef Name='Title' /></ViewFields>",
 CAMLRowLimit:1,
  
// we're not finished...more coming!

  });

Next we call a function that runs when everything is complete. (Be sure to read the documentation on the codeplex for an explanation of why the code should be SPFilterNode instead of find). Ok, the code below first sets a variable called “url”. We set this from the EncodedAbsUrl variable. Don’t forget to include ows_ before the variables when you call them here. Next we have an if statement that tests whether or not the returned item is a document. This is not very relevant for this tutorial, but it’s good to see what happens. Because this is not a document, it’s a list item, the code inside the if statement will run. SharePoint URLs are stored really horribly, so this takes out all the junk and formats it nicely. It cuts off everything after the last forward slash and replaces it with “/Post.aspx?ID=” (this is the default viewing page for a SharePoint post). Then it brings in the ID to append to the URL. Finally, we set a variable called “link”, using the newly formatted URL as the href tag and putting our Title as the anchor text. And to wrap it all up we locate the span we created earlier using jQuery and append the new link we’ve created. The link will be put in dynamically after the page has loaded!

completefunc: function (xData, Status) {
      $(xData.responseXML).SPFilterNode("z:row").each(function() {
      	var url = $(this).attr("ows_EncodedAbsUrl") + "";
      	if(($(this).attr("ows_EncodedAbsUrl") + "").match(/000$/))
      	{
      		url = url.substring(0, url.lastIndexOf("/", url.length));
      		url = url + "/Post.aspx?ID=" + $(this).attr("ows_ID");
      	}
         var link = "<a href='" + url + "'>" + $(this).attr("ows_Title") + "</a>";
        $("#sitecollectionlink").append(link);
      });
    }

So hopefully this tutorial was fairly straightforward. If you got lost, don’t worry, leave a comment and I’ll help you out. And for your ease, the full code is below. Copy and paste to your heart’s content!

Final Result

Copy and paste this into your page and you should be good to go. Remember to change the path to your javascript and the webUrl to your list.

<script type="text/javascript" src="/Style%20Library/scripts/jquery.SPServices-0.7.0.min.js"></script>

<script type="text/javascript">
$(document).ready(function(){
$().SPServices({
operation: "GetListItems",
async: false,
webURL: "/YOUR-SITE/CHANGETHIS",
listName: "Posts",
CAMLViewFields: "<ViewFields><FieldRef Name='EncodedAbsUrl' /><FieldRef Name='Title' /></ViewFields>",
CAMLRowLimit:1,
completefunc: function (xData, Status) {
$(xData.responseXML).SPFilterNode("z:row").each(function() {
var url = $(this).attr("ows_EncodedAbsUrl") + "";
if(($(this).attr("ows_EncodedAbsUrl") + "").match(/000$/))
{
url = url.substring(0, url.lastIndexOf("/", url.length));
url = url + "/Post.aspx?ID=" + $(this).attr("ows_ID");
}
var link = "<a href='" + url + "'>" + $(this).attr("ows_Title") + "</a>";
$("#sitecollectionlink").append(link);
});
}
});
});
</script>

<span id="sitecollectionlink">Latest Blog Article:</span>

Create a jQuery + SharePoint instant search/filter

We’re going to use jQuery and SharePoint to create an “instant” search/filter of a Content Query WebPart and/or List View. This uses the .find(), :contains(), .val(), .hide(), .show(), :not(), .change(), and .keyup() jQuery codes. You can learn all about those from the jQuery documentation. This is all client-side, and only deals with what shows on the page. I’m not going to deal with any server requests, pagination of lists, etc. That’s for later.

Check out the video tutorial below:

Skip ahead:

You’ll be creating something like this:

Step 1: Load jQuery script in your master page

Because our SharePoint installation is secured, I downloaded the latest jQuery build instead of sourcing it from online. So my script in the master page looks like this:

<script type="text/javascript" src="/Style Library/scripts/jquery.js"></script>

Step 2: Create a page with a CQWP or a list view

Doesn’t matter which one you create, but just have some content we can filter.

Step 3: The Code

I built a lot of this from scratch using the jQuery documentation, but a big shout-out goes to Kilian Valkhof’s article, which helped me organize a lot of what I had. This first part enables case-insensitive searching. It came from Kilian Valkhof, who apparently sourced it from Mike Merrit’s LiveFilter jQuery Plugin, but I’m not sure. Either way, I didn’t write it :). Note:if you use this expression, it means you need to change every instance of contains (small C) to Contains (capital C).

<script type="text/javascript">// <![CDATA[
jQuery.expr[':'].Contains = function(a,i,m){return (a.textContent || a.innerText || "").toUpperCase().indexOf(m[3].toUpperCase())>=0;};

Now we start our function anytime the search input box is changed. Once it’s changed, it sets the value of a variable we have called “txt”.

$(document).ready(function(){
  $("input.search").change(function() {
      var txt = $("input.search").val();

Here we have an IF statement that just checks if there is indeed something in the search box, ELSE everything goes back to normal. If there is something inside the search input box, we are going to do two things. First, we’ll find any row that does NOT contain the string, and we’ll hide that row. Then we’ll find any row that DOES contain that string, and we’ll show that row. Finally, we chain a “keyup” function to the change function so that as we type everything is happening all together.

    if (txt) {
     $("#WebPartWPQ4").find("tr.ms-itmhover:not(:Contains("+txt+"))").hide();
     $("#WebPartWPQ4").find("tr.ms-itmhover:Contains("+txt+")").show();
    } else {
     $("#WebPartWPQ4").find("tr.ms-itmhover").show();
    }
  }).keyup(function(){$(this).change();
 })
})
// ]]></script>

And last but not least, we’ll create a simple search input box with a class of “search”. My styling is attached, feel free to erase and do your own:

<div style="padding: 5px; border: 1px solid #cccccc; width: 60%; margin: 10px auto 0pt; background: none repeat scroll 0% 0% #efefef; display: block;">
<h3 style="text-align: center;">Instant search: <input class="search" style="padding: 10px;" type="text" /></h3>
</div>

Step 4: Final touches

The final step is to put this code inside a Content Editor WebPart (I know, I know, but this is for the sake of this tutorial, definitely not best practice). You’ll have to change the target it’s searching and replace it based on whether or not you’re using a CQWP or a list view. A few tips:

#WebPartWPQ4 is the ID of the webpart on my page, but it might change depending on how many webparts you have, what kind they are, etc.

tr.ms-itmhover seems to be the correct selector for any row in a list view

For searching in a Content Query WebPart, I use this:

find("a:Contains("+txt+")").parents("li.dfwp-item").show();

Note that I used parents instead of parent because the latter only searches one level up. CQWP list items are so intricately embedded deep down that you have to find the text inside the link, and then hide the whole list item. Just play around with it, let me know if you need any help.

Learning Sharepoint 2010 Branding

If you’re looking for a great resource to begin learning how to brand and design in Sharepoint 2010, check out Professional Sharepoint 2010 Branding and User Interface Design. It’s a great read, and if you purchase through my link, it helps pay for my hosting!

Or you can purchase the Kindle Version

Create a Classifieds Listing using SharePoint 2010

Creating a “classifieds” listing in Sharepoint 2010 is really easy. You just need a list with a custom column or two, and some pages.

Here’s the list setup:

For my category choices I have: Community Events, Advertisements, For Sale, Free Stuff, General Discussion Topics, etc. Whatever you want to do. Then what you can do is create a landing page that has 4 or 5 webpartzones (again, totally up to you). In those webpartzones place some CQWPs that pull all the items within a specific category, sorted by created date (descending of course). I have customized the itemstyle.xsl page to show the link to the item followed by a really short formatted date. Here’s the xsl for that (see my post on customizing itemstyle.xsl):

<xsl:template name="DiscussionItem" match="Row[@Style='DiscussionItem']" mode="itemstyle">
<xsl:variable name="vv1">
     <xsl:value-of select="@LinkUrl"/>
</xsl:variable> 
<div class="classified-item">
 <a href="{$vv1}"><xsl:value-of select="@Title"/></a> (<xsl:value-of select="ddwrt:FormatDateTime(string(@Created),1033,'MMM-dd')"/>)</div>
</xsl:template>

You’ll wind up with something like this:

To create a new listing, click “Add New Item” (this is a button created in a CEWP that goes to the “new item” form aspx page), select the correct category, input the info, and click “save”.

My SharePoint Favorites

Microsoft’s SharePoint Site
Nothing But SharePoint
Our SharePoint Experience
Kyle Schaeffer’s Blog
Get The Point

Setting SharePoint Blog Permissions

Every time I create a blog in SharePoint I do two things.

  1. Break permissions on the blog, and grant the user owner-level permissions
  2. Break permissions on the comments list. Then grant all users contribute-level permissions so they can add comments.