In the last two months I’ve been deep in the middle of developing a public facing website. I’m trying to dev with a multitude of different methods to gain expereience, however I’ve been falling into the jQuery with SPServices a lot. Mostly because at first it was easier to get information up on the page without having to develop a new webpart and then deploy it, which then requires a change management form. It was also easier to manipulate the information and put one webpart with multiple tabs and multiple divs which where controlled by the tabs. But then I needed one of the divs to get content from a Pages directory. well it took a couple hours, but then I remembered that those are also “lists”. So now I can get all the info with SPServices without the need of developing a webpart to do the same thing and I can get it to “market” faster. Many thanks to Mark Rackley (@mrackely & http://www.sharepointhillbilly.com) and Marc Anderson (@sympmarc & http://sympmarc.com).
Now if I can just get that little Mark Rackley voice out of my head “bad jQuery can bring down your farm…”, sure sure, but my stuff always works sometimes.
I know, I know you’re only here for the code examples. Well you need to be full aware that I have purposely not put all the code in here. You need to figure some of it so you can understand how it all works. Otherwise I’ve just given you a very in depth, yet simple, script and you put it in without understanding it. That’s dangerous and Mr. Rackley will probably hunt me down, point his finger and laugh hysterically and I’ll have to hear him say “I Told You So” or at very least mock me on twitter.
The End Goal is:

First you need to create your Lists. I pull from three Lists and a subsite Pages. Then on the pages you want you need to setup a content editor. In this I use two divs, a UL and script element reference a .js in the SiteAssets. You might also want to add the style to your CSS file. I like a lot of what Design Chemical has to offer. I use the simple tabs in the Simple Tabs AJAX example. I also use Font Awesome.
/*will be an array to use in the document ready to split the UL's of the Homepage Section Items so they show up as two columns if there are more then what fits in the box.*/
var hpSections = new Array();
//this is where the script starts after the page is loaded
$(document).ready(function(){
/*Stupid SharePoint adds blank space if you don't type anything in a content editor. So you have to clear out the div
before you do anything, otherwise it has wierd spacing issues. */
$("#homepageItemsContent").html("");
//Fixes bug where tabs fills up with multiple set of tabs when modifing other webparts
$("#tabs").empty();
GetSections();
//loop through array and splitUL() will correct if necessary Used inconjunction with line 1
//DY 04/16/2012 I forgot to consider the length of the titles before I included this split function.
//var len=hpSections.length;
//for(var i=0; i<len; i++) {splitUL(hpSections[i],9);};
//set the click function to do nothing
$("#tabs li a").click(function(){return false});
//set the mouseover function
$("#tabs li a").mouseover(function(){
//Hide all the divs in the content section
$('#homepageItemsContent div').hide();
$("#tabs li a").removeClass('current');
var correctedLink=this.href.split("/")[4];
$(this).addClass('current');
$('#'+correctedLink+"Section").show();
return false;
});
});
function GetSections(){
var method="GetListItems";
var list="Homepage_Sections";
var fieldsToRead="<ViewFields><FieldRef Name='LinkTitle' /><FieldRef Name='List' /><FieldRef Name='Order' /><FieldRef Name='RowLimit' /></ViewFields>";
var query="<Query><Order><FieldRef Name='Order' /></Order></Query>";
//Here is our SPServices Call where we pass in the variables that we set above
$().SPServices({
operation: method,
async: false, //if you set this to true, you may get faster performance, but your order may not be accurate.
listName: list,
CAMLViewFields: fieldsToRead,
CAMLQuery: query,
//this basically means "do the following code when the call is complete"
completefunc: function(xData, Status){
//this code iterates through every row of data returned from the web service call
$(xData.responseXML).SPFilterNode("z:row").each(function(){
//here is where we are reading the field values and putting them in JavaScript variables
//notice that when we read a field value there is an "ows_" in front of the internal field name.
//this is a SharePoint Web Service quirk that you need to keep in mind.
//so to read a field it is ALWAYS $(this).attr("ows_");
//get the fields we want to display
var Title=($(this).attr("ows_LinkTitle"));
var List=($(this).attr("ows_List"));
//SharePoint has every number as a decimal. I only want the value before the decimal.
var Order=($(this).attr("ows_Order")).split(".")[0];
var RowLimit=($(this).attr("ows_RowLimit")).split(".")[0];
//Can't uses spaces in IDs or javascript, so we have to correct them.
var correctedTitle = Title.replace(/ /g,"");
//push correctedTitle to the Array
hpSections.push(correctedTitle);
//call a function to add the data from the row to a table on the screen
AddRowToTab(Title,List,Order,correctedTitle);
//Load the div with the content
GetSectionContent(List,Title,RowLimit);
});
}
});
}
function AddRowToTab(Title,List,Order,correctedTitle){
//Add a new div to the holder
$("#homepageItemsContent").append("<div id='"+correctedTitle+"Section'><ul id='"+correctedTitle+"'></ul></div>");
//Add the tab to the UL
$("#tabs").append("<li class='homepageTab' id='"+correctedTitle+"Tab'><a href='"+correctedTitle+"' class='sectionTab'>"+Title+"</a></li>");
if(Order==100){
$("#"+correctedTitle+"Section").show(); $("#"+correctedTitle+"Tab a").addClass('current');
}else{
$("#"+correctedTitle+"Section").hide();
};
}
function GetSectionContent(List,Title,RowLimit){
//The Web Service method we are calling, to read list items we use 'GetListItems'
var method = "GetListItems";
//We need to identify the fields we want to return. You can see here that we are using the internal field names.
var fieldsToRead = "<ViewFields><FieldRef Name='LinkTitle' /><FieldRef Name='Link' /><FieldRef Name='Section' /><FieldRef Name='Icon' /></ViewFields>";
//this is that wonderful CAML query I was talking about earlier. This simple query returns
//ALL rows by saying "give me all the rows where the ID field is not equal to 0". I then
//tell the query to sort the rows by the Title field. FYI: a blank query ALSO returns
//all rows, but I like to use the below query because it helps me know that I MEANT to
//return all the rows and didn't just forget to write a query
var query = "<Query><Where><Eq><FieldRef Name='Section'/><Value Type='Text'>"+Title+"</Value></Eq></Where>"+
"<OrderBy><FieldRef Name='Sub_Section'/><FieldRef Name='ItemDate' Ascending='False' /><FieldRef Name='ID' Ascending='False' /><FieldRef Name='LinkTitle'/></OrderBy></Query>";
//Here is our SPServices Call where we pass in the variables that we set above
if(List=="[the /Pages/ List GUID]"){
//This is currently hard coded as I can't figure out another way to do this. This Applies to the News sub site.
$().SPServices({
operation:"GetListItems",
async: false, //if you set this to true, you may get faster performance, but your order may not be accurate.
listName:List,
CAMLViewFields: "<ViewFields><FieldRef Name='LinkFilename' /><FieldRef Name='Title' /><FieldRef Name='ArticleStartDate' /></ViewFields>",
CAMLQuery: "<Query><Where><Neq><FieldRef Name='LinkFilename'/><Value Type='Text'>default.aspx</Value></Neq></Where>"+
"<OrderBy><FieldRef Name='ArticleStartDate' Ascending='False' /></OrderBy></Query>",
completefunc: function(xData, Status){
$(xData.responseXML).SPFilterNode("z:row").each(function(){
var newsItem=($(this).attr("ows_LinkFilename"));
var Title=($(this).attr("ows_Title"));
var Link="/News/Pages/"+newsItem;
var Section="News";
var Icon="icon-file icon-large";
AddItemToUL(Title,Link,Section,Icon);
});
}
});
}else{
$().SPServices({
operation: method,
async: false, //if you set this to true, you may get faster performance, but your order may not be accurate.
listName: List,
CAMLViewFields: fieldsToRead,
CAMLQuery: query,
CAMLRowLimit: RowLimit,
//this basically means "do the following code when the call is complete"
completefunc: function(xData, Status){
//this code iterates through every row of data returned from the web service call
$(xData.responseXML).SPFilterNode("z:row").each(function(){
//here is where we are reading the field values and putting them in JavaScript variables
//notice that when we read a field value there is an "ows_" in front of the internal field name.
//this is a SharePoint Web Service quirk that you need to keep in mind.
//so to read a field it is ALWAYS $(this).attr("ows_");
//get the title field (Link Title)
var Title=($(this).attr("ows_LinkTitle"));
var Icon=($(this).attr("ows_Icon"));
if(Icon==null){Icon="icon-chevron-right icon-large";}else{Icon=Icon+" icon-large";};
//get the url, SharePoint stores a url in the form of
//We only want the url. To accomplish this we use the javascript "split" function
//which will turn into an array where the first element [0]
//is the url. Catch all that? if you didn't this is another reason you should be
//a developer if you are writing JavaScript and jQuery
var Link = ($(this).attr("ows_Link")).split(",")[0];
//var Sub_Section = ($(this).attr("ows_Sub_Section"));
//This has a wierd value and spaces, hence the reason we have all of this in there, to clean it up.
//Not all list have a look up column for Section. Therefore we check if the # is there first before we split so it doesn't barf. (DY)
var Section = ($(this).attr("ows_Section").replace(/ /g,""));
if(Section.indexOf("#") !== -1){Section=Section.split("#")[1];};
//call a function to add the data from the row to a table on the screen
AddItemToUL(Title,Link,Section,Icon);
});
}
});
};
}
function AddItemToUL(Title,Link,Section,Icon){
$("#"+Section).append("<li class='"+Icon+"'><a href='"+Link+"'>"+Title+"</a></li>");
}
function splitUL(ulName,noDepth){
//http://snipplr.com/view.php?codeview&id=15178
$('#'+ulName).each(function(i){
if($(this).find("li").size()>noDepth){
var colsize = Math.round($(this).find("li").size() / 2);
var ulClass = $(this).attr('class');
$(this).find("li").each(function(i){
if (i>=colsize){
$(this).addClass('splitcol_right');
}
});
$(this).find('.splitcol_right').insertAfter(this).wrapAll("<ul class='"+ulClass+"'></ul>");
$('#'+ulName+":first-child").css("padding-right","25px");
}
});
}