Skip Ribbon Commands
Skip to main content
Home
Fewer big words, more pretty pictures.
January 30
A Dummies Guide to SharePoint & jQuery – An Easy to Use Content Slider

So, in my last post we learned how to read SharePoint list data using SPServices:

    A Dummies Guide to SharePoint & jQuery - Reading List Data With SPServices

Now, let's add to that and create something useful. Let's use the data we read in that blog post and create a Content Slider with it. Sound like a plan?

If you are lazy like I am, and lack creativity like I do, then third party jQuery libraries nicely help mask both of these traits. However finding the right jQuery library that works nicely with SharePoint can sometimes be tricky.

Tips for finding the right jQuery library and integrating it into SharePoint

As an extra added bonus (and at no additional charge), before we jump in and talk about the library I chose to use for the content slider allow me to give you some tips about finding the right jQuery library and integrating it into SharePoint.

Never underestimate the advantage of a well maintained library

It's always a good sign for a library when it is actively maintained; it means you're more likely to get support if you have problems or questions. It also means you'll generally be able to get your hands on documentation to help you take full advantage of what the library can do. Conversely, a library without support or documentation may have hidden pitfalls that you are unaware of until you are well past the point of no return.

Test on your target browsers

There are a lot of cool jQuery libraries out there for doing charts, graphs, calendars, animations, and pretty much anything else you can think of. However, check to make sure it works for your target browser. Many libraries use styles that look bad or flat out don't work in IE. Also, if you throw IE6 into the mix your choices fall dramatically. But really, if you are worried about IE6 you have far bigger problems than finding a good jQuery library. J Regardless, before you even download a library to play with it, make sure it works on the browsers you will be using.     

Duplicate the file structure

So, do you have a separate document library for scripts, style sheets, and images? Well… I hope you are flexible about that, at last during development. Many jQuery libraries rely on a style sheets and images all working together under some predetermined directory structure. If you separate these files into different document libraries you are making your life more difficult than it has to be. If you are dead set on all the files being in a different file structure then you might invest many hours only to discover that the library does not work in SharePoint for some other reason.

Make sure it works vanilla / be wary of styles

Which brings me to my final point, before you go to the time and effort to fully implement a jQuery library in SharePoint make sure you can at least get the library to work in SharePoint using one of the various examples that the library hopefully has provided for you. It is all too common for a jQuery library to commandeer styles that SharePoint relies on; often making your SharePoint site completely unusable. Sometimes these styles can be fixed with a couple of small tweaks, and other times it could take hours depending on the library.

Our library of choice: Awkward Showcase - http://showcase.awkwardgroup.com/

Why did I choose this library over others? Well, its transition effects look good in IE, it's got good documentation, it's free, and most importantly it works well with SharePoint. The only downside is that it does not look like the developers are actively supporting it anymore? Bummer… but other than that I've been very impressed.

So, download the library files and let's get started.

The files

First thing we need to do is upload the Awkward Showcase files to our SiteAssets document library. Again, to make our life easier, we are going to create a "css" folder and an "images" folder to hold all of the necessary files. For my purposes I need the following files:

/SiteAssets/jquery.aw-showcase.min.js
/SiteAssets/css/style.css

I also uploaded all the images the library uses even though I may not need them all now:

/SiteAssets/images/arrows.png
/SiteAssets/images/arrows-small.png
/SiteAssets/images/black-opacity-40.png
/SiteAssets/images/ black-opacity-40.png
/SiteAssets/images/ black-opacity-60.png
/SiteAssets/images/ black-opacity-80.png
/SiteAssets/images/plus.png
/SiteAssets/images/white-opacity-40.png
/SiteAssets/images/ white-opacity-60.png
/SiteAssets/images/ white-opacity-80.png

The tweaking

So, remember how I said the style sheets can sometimes interfere with SharePoint? Well, this library is no different in that respect. Fortunately, all I had to do was delete the first 56 lines of the style sheet. So, go ahead and do that as well.

You will also need to go through and tweak the style sheet for the dimensions of your content slider. When things don't line up quite right, arrows don't show up, or something else is off, the first place to look is the style sheet.

The Script

Now that we have our library and all supporting files in place, and removed some of the unwanted style sheet entries, it's time to write our script to implement the content slider in SharePoint. To accomplish this I'm going modify the script we used in the previous blog post (again that was A Dummies Guide to SharePoint & jQuery - Reading List Data With SPServices ).

As a refresher, this script reads the Name, Blog, and Picture for a speaker from my SharePoint List "Speakers". It then just dumps that information out in a very simple table. Basically all we have to do to make this script work for our content slider is:

  1. Add the proper references for the Awkward Showcase files
  2. Instead of having a table as a container for our speaker data, create a div that is needed by the content slider
  3. Instead of appending rows to a table with our speaker information, append divs to our content slider main div
  4. Apply the Content Slider library to the main Content Slider div.

It actually turns out to be a very painless process. Our script ends up looking like the script below. 

<script type="text/javascript" src="../SiteAssets/jquery.min.js"></script>
<script type="text/javascript" src="../SiteAssets/jquery.SPServices.min.js"></script>
<script type="text/javascript" src="../SiteAssets/jquery.aw-showcase.min.js"></script>

<link rel="stylesheet" href="../SiteAssets/css/style.css" />

<script type="text/javascript">


//this is where the script starts after the page is loaded
$(document).ready(function() { 

    GetSpeakers();

});

function GetSpeakers()
{
        //The Web Service method we are calling, to read list items we use 'GetListItems'
        var method = "GetListItems";
        
        //The display name of the list we are reading data from
        var list = "Speakers";

        //We need to identify the fields we want to return. In this instance, we want the Name (Title),
        //Blog, and Picture fields from the Speakers list. You can see here that we are using the internal field names.
        //The display name field for the Speaker's name is "Name" and the internal name is "Title". You can see it can 
        //quickly become confusing if your Display Names are completely differnt from your internal names. 
        //For whatever list you want to read from, be sure to specify the fields you want returned. 
        var fieldsToRead =     "<ViewFields>" +
                                "<FieldRef Name='Title' />" +
                                "<FieldRef Name='Blog' />" +
                                "<FieldRef Name='Picture' />" +
                            "</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>" +
                            "<Neq>" +
                                "<FieldRef Name='ID'/><Value Type='Number'>0</Value>" + 
                            "</Neq>" +
                        "</Where>" +
                        "<OrderBy>" + 
                            "<FieldRef Name='Title'/>" +
                        "</OrderBy>" +
                    "</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 some JavaScript variables
                            //notice that when we read a field value there is an "ows_" in front of the 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_<internal field name>");
                            
                            //get the title field (Speaker's Name)
                            var name = ($(this).attr("ows_Title"));
                            
                            //get the blog url, SharePoint stores a url in the form of <url><comma><description>
                            //so we only want the <url>. To accomplish this we use the javascript "split" function
                            //whch will turn <url><comma><description> 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 blog = ($(this).attr("ows_Blog")).split(",")[0];
                            
                            //same thing as the blog, a picture is stored as <url><comma><alt text>
                            var pictureUrl = ($(this).attr("ows_Picture")).split(",")[0];
                            
                            //call a function to add the data from the row to a table on the screen
                            AddRowToSlider(name,blog,pictureUrl);
                            
                        });
			//After we have processed all the rows, invoke the slider
                        StartSlider();                
                    }
        });

}

function StartSlider()
{
    //invoke the Content Slider on the div with the id "showcase"
     $("#showcase").awShowcase(
        {
            content_width:  600,  //width for my content (entire slider is wider)
            content_height: 200,  //height for my conebt (entire slider may be taller)
            auto:             true, //auto scroll the slides
            continuous:        true, //keep the scrolling
            arrows:            true, //show arrows so user can click through to sliders
            interval:         4000  //show each slide for 4 seconds
        });        

}

//Add a slide div (class='showcase-slide') to our content slider div (<div id="showcase" class="showcase" />)
//and add content div to our (class='showcase-content') slide div
//Again, very simple example, the content of the slider is a table 
//with the speakers picture on the left, and their name and blog on the right
function AddRowToSlider(name,blog,pictureUrl)
{
    $("#showcase").append("<div class='showcase-slide'>" +      //slide container
                            "<div class='showcase-content'>" +  // content container
                                "<table width='600'><tr>" +     //table with our speaker info
                                    "<td align='left'><img src='" + pictureUrl+ "'></td>" +
                                    "<td align='right'><h1>" + name  + "</h1><br>" +
                                    "<h3><a href='" + blog + "'>" + blog + "</a></h3></td>" +
                                "</tr></table>" +
                            "</div>" +
                        "</div>");
                                
}

</script>

<!-- main div container for content slider -->
<div id="showcase" class="showcase" />

As you can see, we didn't have to change much.

If you want to see the script in action you can view it here: http://www.sharepointhillbilly.com/demos/SitePages/SpeakerSlider.aspx This is also the same slider that I'm using on the main page of my blog.

There are a lot more options with the slider that I haven't even looked at and I have just barely scratched the surface with what it can do. It's times like these that I wish I was more of a designer so I could make it look really sharp. I'll leave that up to you guys though, I'll give you the tools to implement it, if you can help me make it look pretty? Deal?

Anyway, there you go… a hopefully-easy-to-implement jQuery Content Slider for SharePoint. If you want to understand what all the other options are for the slider, be sure to checkout the Awkward Group's website: http://www.awkwardgroup.com/sandbox/awkward-showcase-a-jquery-plugin/ 

Interestingly enough, the above url does not work for IE, it's throwing a JavaScript error :) But it seems to open fine in Chrome.

Thanks again for stopping by. I'm starting to run out of ideas for my Dummiers Guide series, so please feel free to suggest some others.

January 25
A Dummies Guide to SharePoint & jQuery - Reading List Data With SPServices

My most excellent and intelligent friend Lori Gowin (@lorigowin) was quite frustrated this evening because she was having issues using SharePoint and jQuery to do an image slider. After I taunted her for a while about “This is why non-developers should not be doing jQuery” I stepped down off my high-horse and thought it might be helpful to write a blog post to help her with one of the integral parts us using an image slider: reading data from a SharePoint list. 

I know there are several blogs out there that deal with examples of reading list data from SharePoint using things like Ajax, SPServices, the Client Object Model, and of course the Server Object Model, but obviously there is still an unmet need for those people who may not know where to start and just need to know the basics. Well, this blog post is for you guys. If I do my job well (which is debatable most days), after this post you will be able to read list data from a SharePoint list using jQuery and SPServices. 

The Foundational Stuff

So, before we get to the meat of this blog post we need to make sure you have a few files in place and understand some of the basics.

Necessary jQuery files

First you need to download the latest jQuery and SPServices libraries. If you are going to be following this blog post exactly, make sure you put them in your “SiteAssets” document library.
 
Apparently there is an issue with using SPServices pre 0.7.0 and jQuery version 1.7+. More information about this can found at: http://sympmarc.com/2011/11/08/problem-with-jquery-1-7-and-spservices/ And thanks again Mr. Marc Anderson for all your efforts authoring and maintaining SPServices.
 
You can download SPServices here (I’m currently using version 0.7.0) and jQuery here (I’m currently using version 1.6.4). As I stated in my blog post A Dummies Guide to SharePoint and jQuery–Getting Started I like to place my scripts in a central document library that users have access to. This gives you the ability to use the awesomeness that is metadata and versioning that Document Libraries provide as well as ease of maintenance (especially during development). In addition I like to remove the version of the script from the script name and put the version in a field. For instance, I rename “jquery-1.6.4.min.js” to “jquery.min.js” and I create a field in my Document Library called “Script Version” and specify 1.6.4.  Make sense? Maybe the screenshot below will help:
doclib.jpg
This gives me the ability (after THOROUGH testing) to just upload the next version of a library and not have to modify any scripts or pages that may be referencing the old script.

SPServices –> SharePoint’s Web Services –> CAML –> Internal field names

SPServices uses SharePoint’s Web Services to retrieve data. SharePoint’s Web Services uses the oh-so-wonderful CAML query language.  It is important to understand the basics of CAML because you will need to learn to write queries that only return the data you need from your SharePoint list. Yes, I did happen to write an intro blog on CAML if you want to better understand it: Another Intro to CAML Blog.
 
In addition, CAML queries and responses use the Internal field names of SharePoint List fields, and NOT the Display names. So, you need to know how to find the internal field name for a field in a list item. There are several ways to do this, but I still find myself using the poor man’s method. Which is:
 
1) Go to the List  Settings page for your list.

listsettings.jpg

2) Click on the name of the field you want to find the internal name for
listsettings2.jpg

3) Go to the end of the url and look for the “&Field=” parameter, what follows that is the internal field name.
changecolumn.jpg
Yes, many times the internal field name will match the display name. However, if someone happens to put a space or some special character in the field name, the internal field name is not at all what you would expect. Take a look at what happens when we create a field with the name “My Field & Yours”:
messedupname.jpg
Did you see that? The internal field name for “My Field & Yours” is “My%5Fx0020%5FField%5Fx0020%5F%5Fx0026%5F%5Fx00”. Yes.. you read that correctly. Plus you also need to go through and replace all of the “%5F”’s with “_”’s before putting the field in your query. So your CAML query would need to use “My_x0020_Field_x0020__x0026__x00” for the query. FUN huh?  Which brings up a Best Practice. ALWAYS  create your field names WITHOUT spaces and special characters. After the field is created you can go back and add spaces and special characters. Changing the display name after the field is created does NOT affect the internal field name. Got it? Can we move on now? Do you understand what an internal field name is and how to get it? Yes, as I said, there are other ways to get internal field names, but I seem  to keep going back to this one. If you have a method you are enamored with, please feel free to share in the comments.

So… why SPServices?

Your final question before we get started (maybe your first?) may be WHY use SPServices instead of something like the Client Object Model or just calling the SharePoint Web Services directly? Excellent… you walked right into my trap. The Client Object Model only works in SharePoint 2010 and does not work for anonymous users. SPServices works the same in both SharePoint 2007 and 2010 and works just fine with anonymous users as long as anonymous users have access to the pages and the scripts. As far as just calling the Web Services directly? Well, that’s basically what SPServices does except it takes care of the heavy lifting for you and wraps the Web Service methods in easy to use functions. So, if you prefer to manually write SOAP envelopes and all that fun stuff, have at it.

Let’s Get To It!

Now that we have all that minutia out of the way, let’s dig into this script and get it working. First thing we need to do is identify which List and fields we want to retrieve data from. For the purposes of this blog lets go back to one of my previously used lists called “Speakers”. From this list, I want to retrieve the speakers Name, Picture, and Blog url.  I will then insert this data into a standard HTML table on the page. I wanted to keep this script as simple as possible for you newbies, so I am not doing any advanced processing with the row data.
 
Please look at the very heavily commented script below to understand some of the nuances of using SPServices and SharePoint’s Web Services:
<script type="text/javascript" src="../SiteAssets/jquery.min.js"></script>
<script type="text/javascript" src="../SiteAssets/jquery.SPServices.min.js"></script>

<script type="text/javascript">


//this is where the script starts after the page is loaded
$(document).ready(function() { 

    GetSpeakers();

});

function GetSpeakers()
{
        //The Web Service method we are calling, to read list items we use 'GetListItems'
        var method = "GetListItems";
        
        //The display name of the list we are reading data from
        var list = "Speakers";

        //We need to identify the fields we want to return. In this instance, we want the Name (Title),
        //Blog, and Picture fields from the Speakers list. You can see here that we are using the internal field names.
        //The display name field for the Speaker's name is "Name" and the internal name is "Title". You can see it can 
        //quickly become confusing if your Display Names are completely differnt from your internal names. 
        //For whatever list you want to read from, be sure to specify the fields you want returned. 
        var fieldsToRead =     "<ViewFields>" +
                                "<FieldRef Name='Title' />" +
                                "<FieldRef Name='Blog' />" +
                                "<FieldRef Name='Picture' />" +
                            "</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>" +
                            "<Neq>" +
                                "<FieldRef Name='ID'/><Value Type='Number'>0</Value>" + 
                            "</Neq>" +
                        "</Where>" +
                        "<OrderBy>" + 
                            "<FieldRef Name='Title'/>" +
                        "</OrderBy>" +
                    "</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_<internal field name>");
                            
                            //get the title field (Speaker's Name)
                            var name = ($(this).attr("ows_Title"));
                            
                            //get the blog url, SharePoint stores a url in the form of <url><comma><description>
                            //We only want the <url>. To accomplish this we use the javascript "split" function
                            //which will turn <url><comma><description> 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 blog = ($(this).attr("ows_Blog")).split(",")[0];
                            
                            //same thing as the blog, a picture is stored as <url><comma><alt text>
                            var pictureUrl = ($(this).attr("ows_Picture")).split(",")[0];
                            
                            //call a function to add the data from the row to a table on the screen
                            AddRowToTable(name,blog,pictureUrl);
                            
                        });                
                    }
        });

}

// very simple function that adds a row to a table with the id of "speakerTable" 
// for every row of data returned from our SPServices call. 
// Each row of the table will display the picture of the speaker and
// below the speaker's picture will be their name that is a hyperlink
// to the speaker's blog.
function AddRowToTable(name,blog,pictureUrl)
{
    $("#speakerTable").append("<tr align='middle'>" + 
                                "<td><img src='" + pictureUrl + "'><br><a href='" + blog + "'>" + name + "</a></td>" +
                               "</tr>");
                                
}

</script>

<!-- table where our speaker rows will go -->
<table id="speakerTable"><table>
There are a LOT of quirks with the way SharePoint returns different field types. It's always helpful to throw a quick alert($(this).attr("ows_fieldName")); to see what the actual returned value is.
 
At this point, all you need to do now is save the script and upload it to your document library and then link to the script in a content editor web part (or whatever method you choose to get the script loaded on a page).
linkedscript.jpg

If you want to see this script live in action so you can be sure I’m not just making this stuff up you can go to:  http://www.sharepointhillbilly.com/demos/SitePages/GetSpeakers.aspx

And there you have it

So, hopefully I was able to break this down enough to where you can now write your own script to read specific items from a SharePoint List.
 
I highly recommend you bone up on your CAML and only retrieve the rows you care about as this can be a huge impact on performance. Also, keep in mind that alerts are worth their weight in gold.. well.. they don’t actually weigh anything.. but they are still important for quickly debugging issues. If you are having problems, the best place to put an alert is right before the call to GetSpeakers(); as follows:
$(document).ready(function() { 

    alert("your code is at least executing");
    GetSpeakers();

});
 
If you don’t get the alert, then you know your code is not executing at all. This usually means one of your scripts is not loading. If one of your scripts is not loading, it’s because the path to it is not accurate.
 
Ahhhh… debugging jQuery in SharePoint… that is a whole other deep black pit of despair.. are you SURE you want to do this?
 
Anyway, if I need to explain anything in more detail please let me know!  Thanks again for stopping by…

 

January 19
Creating a SharePoint Parent/Child List Relationship–No SPD Version
So, over the years by far my most read blog posts are the ones detailing how to create Parent/Child list relationships in SharePoint and automatically populating the Parent (Lookup) ID of the Child list. Those posts being:

Creating a SharePoint List Parent / Child Relationship - Out of the Box (yes, I know the videos are dead on this one. The VIDEO REMIX post is better anyway)
Passing Multiple Query String Variables Using SPD – Follow Up on Creating Parent / Child List Relationships
Creating a SharePoint List Parent/Child Relationship – VIDEO REMIX
Creating A SharePoint Parent/Child List Relationship– SharePoint 2010 Edition

You’d think at some point I’d stop kicking that dead horse, but no… These blog posts are all still quite active and occasionally spawn further questions. Which brings me to this blog post. A couple of weeks ago I had an email from a gentlemen who wanted to create this Parent/Child list relationship, but his organization decided to not allow the use of SharePoint Designer (SPD). Hey, did you know it’s free? Well, my previous posts had always utilized SPD as an integral tool for creating these relationships. However, it’s very possible to create the same functionality using only JavaScript/jQuery.
 
So, Why don’t we bring that leg back one more time and give that horse a smack while I show you how to create a Parent/Child list relationship in SharePoint 2010 without using SharePoint Designer.

Before we get started

Before we get started, make sure you are familiar with jQuery basics including deploying jQuery, linking scripts to Content Editor Web Parts, and setting SharePoint Form Fields.  Luckily I have a couple of blog posts to help you out with that:

A Dummies Guide to SharePoint and jQuery–Getting Started
A Dummies Guide to SharePoint and jQuery–Getting & Setting SharePoint Form Fields

I’m going to assume you have the document library “SiteAssets” at the root of your Web Application and the jQuery library named “jQuery.min.js” in that document library. We will also be storing any scripts we write for this blog in that same document library.
 
Also, make sure you have the lists that we’ll be using. Just like every previous example we’ll be using the following list structure:

Parent List: “Issue”

Field Name Field Type
All we need is default “Title” field for our needs  
 

Child List: “Time”

Field Name Field Type
IssueID Lookup Field Type on ID field of “Issue” list
Hours Numeric Field Type
 
You can also refer to my video from my earlier blog post on this topic for more step-by-step instructions on how to create these lists. In fact, I’ll just link the video for creating the lists here. (You're Welcome)

Creating Issue and Time List in SharePoint 2012

Lastly, I would like to point out that this method will work in both SharePoint 2007 and 2010, although certain aspects are different in 2007 such as editing default pages (append “&ToolPaneView=2” to the page’s url to get into edit mode in 2007).
 

So, what’s the plan?

So, here are the steps we are going to take to create the list relationship functionality. For those of you comfortable with SharePoint and JavaScript/jQuery maybe this is all you need, for the rest I’ll go through the step-by-step “how” below.
 
1) Edit the default Display Form for the Issue list
a) Add Time list to the page
b) Set up web part connection between the Issue Display Form and the Time list
c) Write a script that overwrites the “Add new item” link and passes in the Issue’s ID as a Query String parameter
2) Modify the default New Item Form for the Time list and add a script that:
a) Sets the value of the IssueID lookup field
b) hides the “Issue ID” field to stop meddling users and their darn dogs from changing it
That’s all there is to it. Not too hairy I hope? let’s get started and I’ll walk you through it step by step.

Edit the Default Display Form for the Issue List

Now that you have the requisite lists created, let’s make the necessary modifications to the default Display Form for the Issue List.
First thing we are going to do is add the Time list to the Default Display form of the Issue list. Then we are going to add a Web Part Connection between the Issue Display Form Web Part and the Time list Web Part using the “ID” from the Issue list and the “IssueID” from the Time list as filter members. After this is complete, you will see a list of all associated Time entries for an Issue whenever you view an issue.
 
Edit Default Display Form for Issue, Add Time List, Create Web Part Connection to Filter Time


The next step is to write a script that will overwrite the “Add new item” link of the Time list so that we can call the SharePoint “NewItem2” function to bring up the modal window for a new Time entry as well as pass the parent Issue’s ID to the New Item form as a Query String variable. The following script will be used to accomplish this task. 
 
<!--
    Name: DisplayIssue.js 
-->

<script type="text/javascript" src="/SiteAssets/jquery.min.js"></script>


<script type="text/javascript">

jQuery(document).ready(function($) {

    //get the ID for the Issue from the Query String
    var issueID = getParameterByName("ID");

    //find the element with the "Add new item" link.
    //note that if you have more than one list on your page, this just finds the first one
    var anchorElement = $("a:contains('Add new item')");
    
    //modify the "Add new item" link to call the "NewItem2" function and pass in the Issue ID. 
   //Be sure to put the path to your site below. You can use relative URL to the web application or the FQDN
    $(anchorElement).attr("href","javascript:NewItem2(event,'http://PATH_TO_YOUR_SITE/Lists/Time/NewForm.aspx?IssueID="  + issueID + "');");
    //remove the "onclick" attribute from the anchor element as we aren't using it anymore
    $(anchorElement).removeAttr("onclick");

});

// The following function should really be put into a utility library
// with all of your commonly called functions
//
// no, I didn't write this function from scratch, I found it at
// http://stackoverflow.com/questions/901115/get-query-string-values-in-javascript
function getParameterByName(name)
{
  name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
  var regexS = "[\\?&]" + name + "=([^&#]*)";
  var regex = new RegExp(regexS);
  var results = regex.exec(window.location.href);
  if(results == null)
    return "";
  else
    return decodeURIComponent(results[1].replace(/\+/g, " "));
}

</script>
 
Again, you should really create a utility library and put commonly used functions like “getParameterByName” in it instead of copying the same functions over and over again in your scripts like I’m doing here… and in the next script… Do as I say!! Not as I do!
 
Now that we have our script written and uploaded to our SiteAssets document library, let’s add it to the Issue Display form.
 
Insert DisplayIssue.js script into Issue Display Form

Okay, so at this point we have modified our Issue Display form so that it only shows Time entries associated with the current issue and we’ve added a script that allows us to pass in the ID of the Issue to the Time New Item Form as the Query String parameter “IssueID”.  Which brings us to the next step in the process.
 
Modify the Default New Item Form for the Time List
 
If you haven't fallen asleep yet and have followed all the previous steps, the New Item Form for the Time list now has the ID for the Issue being passed to it in the Query String Parameter “IssueID”. Yes, I know you can’t “see” it because of the modal window, but trust me, it’s there. Have I ever knowingly lied to you before?
 
The next thing we need is a script that can read the “IssueID” Query String parameter value, and then store that value in the “IssueID” Lookup field on the New Time form. The Script below does just that. There are a couple of things I would like to point out about the script before you go pasting it into your solutions:
 
1) Again, you REALLY should create a utility library for “getParamterByName”. I toyed with doing that for you in this blog post, but I really wanted to keep it simple as I know many of you don’t want to be bogged down with the extra details.
 
2) SharePoint has a “feature” with lookup fields in IE where if you have more than 20 items it changes the “select” element into an “input” element. I actually blogged about that if you want to know more at: Setting SharePoint Lookup Lists w/ jQuery (+/- 20 items). I bring this up because I have to take this into account when setting and hiding the IssueID in the script below. You’ll see what I mean.
<!--
    Name: NewTime.js 
-->

<script type="text/javascript" src="/SiteAssets/jquery.min.js"></script>

<script type="text/javascript">

jQuery(document).ready(function($) {

    //get the Issue ID from they query string
    var issueID = getParameterByName("IssueID");

    //Set the corresponding Lookup field value to the Issue ID
    //and hide the field row
    SetLookup("IssueID",issueID);
    
});


// The following functions should really be put into a utility library
// with all of your commonly called functions

//Sets the value of a lookup field whether it is an input or select field. 
function SetLookup( fieldTitle, lookupVal)
{
    //Set default value for lookups with less that 20 items
    if ( $("select[title='" +fieldTitle+ "']").html() !== null)
    {
       $("select[title='"+ fieldTitle +"']").val(lookupVal);    
       //hide the field row
       $("select[title='IssueID']").closest("tr").hide();    

    }
    else
    {
        choices = $("input[title='" +fieldTitle +"']").attr("choices");
        hiddenInput = $("input[title='" +fieldTitle +"']").attr("optHid");
        $("input[id='" +hiddenInput +"']").attr("value",lookupVal)
        
        choiceArray = choices.split("|");
        for (index = 1; index < choiceArray.length; index = index + 2)
        {
            if (choiceArray[index] == lookupVal){
                $("input[title='" +fieldTitle +"']").val(choiceArray[index - 1]);    
                //hide thie field row
                $("input[title='IssueID']").closest("tr").hide();
            }
        }
    }
}


// no, I didn't write this function from scratch, I found it at
// http://stackoverflow.com/questions/901115/get-query-string-values-in-javascript
function getParameterByName(name)
{
  name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
  var regexS = "[\\?&]" + name + "=([^&#]*)";
  var regex = new RegExp(regexS);
  var results = regex.exec(window.location.href);
  if(results == null)
    return "";
  else
    return decodeURIComponent(results[1].replace(/\+/g, " "));
}

</script>
Alright, let’s add the script to the Time list New Item form and make sure it all works. Again, unless I broke something the script is going to read the Query String parameter “IssueID” and set the value of the “IssueID” lookup field to the corresponding value. The script will then hide the IssueID field from the New Time form completing our magical journey into the world of SharePoint for this evening.
 
Insert NewTime.js script into Time New Item Form

Tada… that’s really all there is to it.

And in Conclusion

There you go, setting up a Parent/Child list relationship in SharePoint 2010 without using SPD. I think I may actually like this method best from a maintenance standpoint. Have a better idea on how to accomplish this? Please share with the rest of the class, the comments section isn’t there for spammers to hock their wares…
 
Hopefully most of your questions have been answered? If you’re lucky you will not have to endure another one of these posts from me until vNext. As always, please let me know if I was not clear about something and I’ll see what I can do to explain myself better.
 
One last note, You can build upon this example and pass multiple values from the Parent Display form in the Query String and set multiple fields in the Child’s New Item form, just modify the script to pass more values in the “NewItem2” function, and modify the other script to set more fields. Refer to my previously mentioned blog post A Dummies Guide to SharePoint and jQuery–Getting & Setting SharePoint Form Fields for more information on how you might read and set SharePoint form field values.
 
Thanks again for stopping by, I hope maybe you learned a trick or two.
1 - 3Next

SharePoint Architect, Developer, Blogger, Speaker, Author, and general pain in the butt.
 
Thoughts, views, and opinions expressed in this blog are solely my own.
 
Remember, the Impossible just takes longer.
​​​​