In this positing I’m going to cover utilizing the SPServices codeplex project to build a “Gallery” of sorts. In this demo we’ll be creating a picture gallery but ideally this code be used for any content. The main focus of this article is how to take advantage of the paging capability of the list web service. I found this to be a sparsely document capability and this demo might enlighten some people on how to use it.
Some of you might say, “What’s the point of this. There are so many jQuery galleries and quite frankly they look better!”
Well very true they do look better, and they might even have pagination. The problem with those is that you might have to load all the data on the page before it could perform its magic. This demo will only load the 6 items at a time, and this technique could be used on any type of object that needs pagination, and it’s more of a real world example of how to use the SPServices to make list web services calls using the CAML options for paging.
With all that said, let’s get started. Just want the files? Download the CEWP & gallery.js here
Pre-Requisites:
Download SPServices, and jQuery store them in a folder on your SharePoint site. I’m using SPServices 0.6.0 & jQuery 1.5.1
- First I’ve created an image gallery called – “Gallery”
- Add more than 6 pictures to this library.
- Next edit the page and pop in a Content Editor Web Part, add in your script references.
** gallery.js is the name of our script file that we will be making **
- Next add in the HTML structure that we’ll need.
- Lastly lets add just a touch of style
Attached is the gallery.js, upload that where your other javascript files are and make sure the reference in step 3 is correct.
Let’s take a look at the gallery.js to explain what its doing as well as show you what you can configure. I’ll be jumping around the script but I’m leaving the line numbers in there so you know where I am.
The rowLimit is the number of items to display per page, The list is the name of your List, and the query can be configure at the top of the script. (this can be expanded out to have a selected rowLimit or filters)
The following starts the creation of the gallery. Its contained in a function called Update(). Update will call the three functions to build the gallery. GetItems -> BuildNav -> UpdatePrevNext
This GetItems() function takes a position and a row limit and displays that set of items. The output of the items can be modified inside the $(xData.responseXML).find(“[nodeName=’z:row’]”).each(function(i) { });
Next function BuildNav() builds out the navigation, it does this by making repetive calls to the web service with the row limit and the next position. In terms of performance, the more items you have and the smaller the row limit, then the more web service calls will be made. The less items and higher row limit, then the less web service calls will be made. This section also builds out the initial Prev & Next links.
In line 156 above the build nav will call GetNextPos and it will feed it the current position with a row limit in order for it to return the next position in the pagination
Lastly the script binds to the click events of the pagers, previous and next buttons.
So that’s it .. The finished product. A jQuery type solution to creating a paginated gallery type widget.
Download the CEWP & gallery.js here
Good morning, Thomas.
Can you post up this example on a working page? or can you at least say what the “pos” var expects? From what I saw, it expects some kind of tag, but I need to know what it has inside this tag.
Many Thanks!
this article is so old there has to be better ways to go about this. SPServices has changed a lot since the article. If you’re on SP2013 you could use the javascript client object model (REST) or the client side object modal.
POS if like a token that gets passed, you can figure out what the next token is by just running a query and don’t specify a position. you can put a console.log(xData.responseXML) to view everything that comes back. or alternatively you could use fiddler to see what goes out and what comes back.
There is an example directly in the code. Line 121-131, if you put that in it’s own function and run that once you’ll see the position key come back. You can put a console.log(firstPos) before or after 129 and you’ll see the token in the debug window of the browser.
Hi,
I made some changes & was able to make this work.
But now I am getting issue while i publish the page.
while the pagination works fine when the page is in edit mode.
When i publish the page i get below error:
Object doesn’t support this property or method
Do you have any idea, what might be the issue as to why the code is working fine while the page is in edit mode, but it throws “Object doesn’t support this property or method” error when i publish the page.
Below is the Code :
.gallery-item img
{
height: 150px;
width: 200px;
float: left;
margin-right: 5px;
margin-bottom: 5px;
}
#gallery-pager-controls
{
clear: both;
}
#gallery-pages div
{
float: left;
margin-right: 5px;
}
var rowLimit = 3;
var list = “Gallery”;
var query = “”;
var targetID = “gallery”;
$(document).ready(function(){
Update();
});
function Update()
{
GetItems(“”,rowLimit);
BuildNav(rowLimit);
UpdatePrevNext();
}
function GetItems(pos, rowLimit)
{
//clear any prev content
$(“#gallery”).html(“”);
try
{
pos = pos.replace(/&/g,’&’).replace(/”/g,’"’).replace(//g,’>’);
}
catch(e)
{
}
$().SPServices({
operation: “GetListItems”,
async: false,
listName: “Discovery Series Events”,
CAMLQuery: “No”,
CAMLQueryOptions: “”,
CAMLRowLimit: rowLimit,
completefunc: function(xData, Status) {
$(xData.responseXML).SPFilterNode(“z:row”).each(function(index) {
var strHtml = “”;
var strtitle = $(this).attr(“ows_Title”);
strHtml += “” + strtitle + “”;
$(“#gallery”).append(strHtml);
});
}
});
}
function BuildNav(rowLimit)
{
//Unbind old objects
$(“gallery-prev a”).unbind(‘click’);
$(“gallery-next a”).unbind(‘click’);
$(“.pager a”).unbind(‘click’);
//Clear current nav
$(“#gallery-pages”).html(“”);
var totalItems = 0;
var firstPos = “”;
//execute once to get all items
//not using rowlimit to return all items
$().SPServices({
operation: “GetListItems”,
async: false,
listName: “Discovery Series Events”,
CAMLQuery: “No”,
completefunc: function (xData, Status) {
totalItems = $(xData.responseXML).SPFilterNode(“rs:data”).attr(“ItemCount”)
}
});
//execute again to retrieve first position
//this uses rowLimit
$().SPServices({
operation: “GetListItems”,
async: false,
listName: “Discovery Series Events”,
CAMLQuery: “No”,
CAMLRowLimit: rowLimit,
completefunc: function (xData, Status) {
firstPos = $(xData.responseXML).SPFilterNode(“rs:data”).attr(“ListItemCollectionPositionNext”);
}
});
if(eval(totalItems > rowLimit))
{
$(“#gallery-pages”).append(‘Prev‘);
var pages = Math.ceil(totalItems / rowLimit);
var nextPos = “”;
for(i=1;i<=pages;i++)
{
if(i==1)
{
$("#gallery-pages").append("” + i + ““);
nextPos = firstPos;
}
else
{
if(i==2)
{
$(“#gallery-pages”).append(“” + i + ““);
}
else
{
nextPos = GetNextPos(nextPos, rowLimit);
$(“#gallery-pages”).append(“” + i + ““);
}
}
}
$(“#gallery-pages”).append(‘Next‘);
}
}
function UpdatePrevNext()
{
$(“.pager a”).click(function(){
$(“.pager a”).removeClass(“selected”);
var id = $(this).parent().attr(“id”);
id = id.substring(id.indexOf(‘-‘)+1)
$(this).addClass(“selected”);
});
$(“#gallery-prev a”).click(function(e){
e.preventDefault();
var id = $(“.pager a.selected”).parent().attr(“id”);
id = id.substring(id.indexOf(‘-‘)+1);
//is there an item below?
if(id != 1)
{
$(“.pager”).eq(id-2).find(“a”).click();
var href = $(“.pager”).eq(id-2).find(“a”).attr(“href”);
href = href.substring(href.indexOf(‘”‘),href.length-1);
href = href.split(‘,’);
var page = href[0].substring(1,href[0].length-1);
var rowLimit = href[1].substring(1,href[1].length-1)
GetItems(page,rowLimit);
}
});
$(“#gallery-next a”).click(function(e){
e.preventDefault();
var id = $(“.pager a.selected”).parent().attr(“id”);
id = id.substring(id.indexOf(‘-‘)+1);
//is there an item above?
total = $(“.pager”).length;
if(id != total)
{
$(“.pager”).eq(id).find(“a”).click();
var href = $(“.pager”).eq(id).find(“a”).attr(“href”);
href = href.substring(href.indexOf(‘”‘),href.length-1);
href = href.split(‘,’);
var page = href[0].substring(1,href[0].length-1);
var rowLimit = href[1].substring(1,href[1].length-1)
GetItems(page,rowLimit);
}
});
}
function GetNextPos(pos, rowLimit, query)
{
try
{
pos = pos.replace(/&/g,’&’).replace(/”/g,’"’).replace(//g,’>’);
}
catch(e)
{}
$().SPServices({
operation: “GetListItems”,
async: false,
listName: “Discovery Series Events”,
CAMLQuery: “No”,
CAMLQueryOptions: “”,
CAMLRowLimit: rowLimit,
completefunc: function(xData, Status) {
pos = $(xData.responseXML).SPFilterNode(“rs:data”).attr(“ListItemCollectionPositionNext”);
}
});
return pos;
}
what line specifically does that error on? typically that error is in response to a library not available. like jQuery or SPServices. I’d first view source make sure those links work, then it’s possible your loading jquery twice somewhere.
I tried with jquery.SPServices-2014.01.min.js and jquery-1.11.1.min.js but is not paging correctly. Can anyone help me?
I’m sorry this is a really old post. There might be better ways to handle this now.
Tom,
Thanks for this. I’m not getting the paging to work for numbers greater than 2. Any help?
Did you follow everything exact? I’ll try this out just to make sure it’s working. You have to use the version of jQuery and SPServices as listed in the article or it may not work correctly.
I am having the same issue. Did you ever find a solution?
This article is very outdated at this point. This was written on SharePoint 2007 with very early versions of jQuery & SPServices.
There are definitely better solutions out there at this point for a photo gallery even free webparts if you search for them.
Oops, meant to include path to scripts reply:
I’m hoping you can help me – I’m just getting started with Sharepoint and I’ve tried to implement this solution on my sharepoint (2010 Foundations) site, but so far no success. I created a document library called ‘js’ and uploaded the scripts there. I am using the same versions of jquery and SPServices that you quoted in the Pre-requisites
My picture library is called ‘Gallery’ I’ve copied the CEWP and only changed the src path of the scripts to the scripts are:
The path to my Picture Library is:
/Lee/Gallery/
What am I missing? Any help would be appreciated…
Thomas – thank you for explaining this, I’m trying to use the pagination feature you explain here in another project of mine but I’m facing some issues. BTW I did a Google search for SPServices and Pagination and was brought right in your backyard 🙂 I have never been to your blog before and must say – I’m already a fan of the good solutions you share explain on your blog.
If time permits you, can you show an example of fetching SharePoint list data using SPServies but then displaying the list data in datatables?. I already have created a fully working ASPX page getting SP list data using SPServices and then displaying it in datatables, but for the life of me I can’t seem to get the pagination to work. I want the pagination to make AJAX calls when the user requests it Pg 1, Pg 2 Pg etc and not load all the data into the DOM in one AJAX call – which my page is currently doing, thereby slowing the performance.
thanks
Thanks for taking the time to check out my blog! I took a look at the datatables to see how that might work. I will take crack at it this weekend and see if I can get that working.
The solution I posted would created the pagination portion. Just like you want but I’m guessing that your using the datatables for some of the other functionality as well. I love a challenge so I’ll let you know what I come up with.
Just so I know, what are the main features of the datatables that you are using.. excluding the pagination? I have an idea for an alternate solution which would use the some of the code in the post to build some html structure of data and use some form of jquery scripts to make a sortable table OR find another script that would meet your requirements.
-td
After doing some more research I think your best bet is to use jquery tablesorter (http://tablesorter.com/docs/) That doesn’t have a pagination piece (initially – but plugin available).. so you could use what I have explained to build the individual pages and then enable this once the new data comes in. The plugin that they have to do pagination would probably require all data on the page as well. This way should be pretty straightforward, Good Luck!
thanks Thomas, I will get working on it and share my experience at a later time.