All posts by Alexander Bautz

Ratings for SharePoint lists

03.03.2010 Updated code for the file “RatingForSharePoint.js” due to a bug occurring when the ID column was hidden, but not placed far right in the view.

I got this request after enabling “rating” of the blog comments:

…How can we implement the thumbs up or down functionality you have on your site to a sharepoint list?

Tony


I have made a solution that uses a separate list to hold all the ratings. There will be written one line in this list for each rating of an item (list item or document).

This solution allows for one rating per item, per user, per session (browser session – new window = new session). There are an option to restrict or allow multiple ratings per user in different sessions.

The rating of the items are available in a list view (plain type, no boxed style), and in grouped plain list views. It is also available in DispForm.

ListView:
IMG

DispForm:
IMG

DispForm if already rated:
IMG

To enable rating of items, you add a calculated column to your list with this code:

=""

Yes, only “equals” and two double quotes. You then assures that this new calculated column and the ID column is visible in the list view (there is an option in the script to hide the ID column).

Then you create a custom list for the ratings, with the name: RatingForSharePoint, and add these fields:

  • Plus The type of information in this column is: Number
  • Minus The type of information in this column is: Number
  • ListUrl The type of information in this column is: Single line of text
  • ItemID The type of information in this column is: Single line of text
  • ListGuid The type of information in this column is: Single line of text
  • ListName The type of information in this column is: Single line of text

As always we start like this:
Create a document library to hold your scripts (or a folder on the root created in SharePoint Designer). In this example i have made a document library with a relative URL of “/test/English/Javascript” (a sub site named “test” with a sub site named “English” with a document library named “Javascript”):
IMG

The jQuery-library is found here. The pictures and the sourcecode refers to jquery-1.3.2.min. If you download another version, be sure to update the script reference in the sourcecode.

The scripts “interaction.js” and “stringBuffer.js” is created by Erucy and published on CodePlex.

The file “sessvars.js” is found here.

The sourcecode for the file “RatingForSharePoint.js” is found below.

Add a CEWP below the listView and add this code:

<script type="text/javascript" src="/test/English/Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/interaction.js"></script>
<script type="text/javascript" src="/test/English/Javascript/stringBuffer.js"></script>
<script type="text/javascript" src="/test/English/Javascript/sessvars.js"></script>
<script type="text/javascript" src="/test/English/Javascript/RatingForSharePoint.js"></script>
<script type="text/javascript">
ratingForSharePoint('Rating',true,true);
</script>

Parameters explained:

  • FieldInternalName: FieldInternalName of the calculated column created above.
  • hideIdCol: true to hide the ID column, false to let it be visible.
  • rateOnlyOnce: true to allow only one rating per user, false to allow multiple ratings (in different sessions)

Add a CEWP below your DispForm, and add this code:

<script type="text/javascript" src="/test/English/Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/interaction.js"></script>
<script type="text/javascript" src="/test/English/Javascript/stringBuffer.js"></script>
<script type="text/javascript" src="/test/English/Javascript/sessvars.js"></script>
<script type="text/javascript" src="/test/English/Javascript/RatingForSharePoint.js"></script>
<script type="text/javascript">
// You must edit this GUID to match THIS list's GUID - this is NOT the GUID of the "RatingForSharePoint"
thisListsGuid = '{77C35652-1D4D-4B09-B58C-D941068D251E}';
ratingForSharePointDispForm('Rating',true);
</script>

Parameters explained:

  • thisListsGuid: This list’s GUID – this is NOT the GUID of the “RatingForSharePoint”
  • FieldInternalName: FieldInternalName of the calculated column created above
  • rateOnlyOnce: true to allow only one rating per user, false to allow multiple ratings (in different sessions)

Read here how to add a CEWP to the NewForm, DispForm or EditForm, how to find the list Guid of your list, and how to find the FieldInternalName of your columns.

The sourcecode for the file “RatingForSharePoint.js” looks like this:

/* Rating for SharePoint lists
 * ---------------------------------------------
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * https://spjsblog.com
 * v1.1
 * LastMod: 03.03.2010
 * ---------------------------------------------
 * Must include reference to:
 *  jQuery - http://jquery.com
 *  interaction.js - http://spjslib.codeplex.com
 *  stringBuffer.js - http://spjslib.codeplex.com
 *  sessvars.js - http://www.thomasfrank.se
 *  RatingForSharePoint.js - This file
 * ---------------------------------------------
*/

// If anonymous the SharePoint variable "_spUserId" does not exist
if(typeof(_spUserId)=='undefined'){
	_spUserId = '';
}
/************************************************************
*********************** ListView Code ***********************
************************************************************/
function ratingForSharePoint(FieldInternalName,hideIdCol,rateOnlyOnce){
if(typeof(ctx)=='object'){
	var thisListsGuid=ctx.listName;
}
	if(typeof(currentRatingObj)=='undefined'){
		currentRatingObj = getRating();
	}
	if(typeof(FieldInternalName)!='undefined'){
		intName = FieldInternalName;
		hideId = hideIdCol;
		rateOnce = rateOnlyOnce;
		// Fiend index of "Rating" column
		$(".ms-viewheadertr th").each(function(){
			if($(this).find('table:first').attr('name')==intName){
				colIndex = $(this).attr('cellIndex');
				displayName = $(this).find('table:first').attr('displayname');
				// Remove filtering possibility
				$(this).removeClass('ms-vh2').addClass('ms-vh2-nograd').html(displayName);
			}
		});
		// Find index of ID column
		$(".ms-viewheadertr th").each(function(){
			if($(this).find('table:first').attr('name')=='ID'){
				IdColIndex = $(this).attr('cellIndex');
				// Hide ID column
				if(hideId){
					$(this).remove();
				}
			}
		});
		if(typeof(colIndex)=='undefined' || typeof(IdColIndex)=='undefined'){
			alert("Both the column with FieldInternalName ""+FieldInternalName+"" and the ID-column must be in the view.");
			return false;
		}
	}

	$("table.ms-listviewtable tbody:not([id^='aggr']) >tr[beenthere!=1]:has(td.ms-vb2)").each(function(){
		$(this).attr('beenthere',1);
		var itemAlreadyRate = false;
		var thisTd = $(this).find("td[cellIndex=" + colIndex + "]");
		var thisIdColumn = $(this).find("td[cellIndex=" + IdColIndex + "]");
		var thisId = thisIdColumn.text()
		if(hideId){
			thisIdColumn.remove();
		}
		var rPos = 0;
		var rNeg = 0;
		if(currentRatingObj[thisId]!=undefined){
			// Previously rated by current user
			if(rateOnce && currentRatingObj[thisId]['ratedByMe']==true){
				itemAlreadyRate = true;
			}
			rPos = currentRatingObj[thisId]['Plus'];
			rNeg = currentRatingObj[thisId]['Minus'];
		}
		// Rated in this session
		if(sessvars[thisListsGuid+thisId]==1 && currentRatingObj!=false){
			itemAlreadyRate = true;
		}

		var str = "<div style='color:gray'>";
		str += "<span><img ";
		if(!itemAlreadyRate){
			str += "onclick='javascript:rateMe("up","+thisId+")' title='Rate Up' ";
			str += "style='vertical-align:middle;cursor:pointer' ";
		}else{
			str += "title='You have already rated this item "+currentRatingObj[thisId]['ratedByMeVal']+"' ";
			str += "style='vertical-align:middle;cursor:no-drop' ";
		}
		str += "src='/_layouts/images/arrupi.gif'></span>";
		str += "<span style='font-weight:bold;' id='rateUp_"+thisId+"'>"+rPos+"</span>";
		str += "<span><img ";
		if(!itemAlreadyRate){
			str += "onclick='javascript:rateMe("down","+thisId+")' title='Rate Down' ";
			str += "style='vertical-align:middle;cursor:pointer' ";
		}else{
			str += "title='You have already rated this item "+currentRatingObj[thisId]['ratedByMeVal']+"' ";
			str += "style='vertical-align:middle;cursor:no-drop' ";
		}
		str += "src='/_layouts/images/arrdowni.gif'></span>";
		str += "<span style='font-weight:bold;' id='rateDown_"+thisId+"'>"+rNeg+"</span>";
		str += "</div>";
		// Write HTML
		thisTd.html(str);
	});
}

function getRating(){
// Path to webservices
wsBaseUrl = L_Menu_BaseUrl + '/_vti_bin/';
var query = "<Where><Eq><FieldRef Name='ListGuid' /><Value Type='Text'>"+ctx.listName+"</Value></Eq></Where>";
var rating = queryItems('RatingForSharePoint',query,['Plus','Minus','ItemID','Author']);
	if(rating.count==-1){
		alert("An error occured in the query:n"+query);
	}else if(rating.count>0){
	ratingObj = {};
		$.each(rating.items,function(i,item){
		var authorIdRaw = item['Author'];
		var authorId = authorIdRaw.substring(0,authorIdRaw.indexOf(';#'));
		var plusVal = item['Plus'];
		var minusVal = item['Minus'];
		if(plusVal==null)plusVal=0;
		if(minusVal==null)minusVal=0;
			if(ratingObj[item['ItemID']]==undefined){
				ratingObj[item['ItemID']]={'Plus':parseInt(plusVal),'Minus':parseInt(minusVal)};
			}else{
				ratingObj[item['ItemID']]['Plus']+=parseInt(plusVal);
				ratingObj[item['ItemID']]['Minus']+=parseInt(minusVal);
			}
			// Rated by current user
			if(_spUserId==authorId){
				ratingObj[item['ItemID']]['ratedByMe']=true;
				if(item['Plus']>0){
					ratingObj[item['ItemID']]['ratedByMeVal']="+1";
				}else{
					ratingObj[item['ItemID']]['ratedByMeVal']="-1";
				}
			}
		});
		return ratingObj;
	}else{
		return false;
	}
}

/************************************************************
*********************** DispForm Code ***********************
************************************************************/
function ratingForSharePointDispForm(FieldInternalName,rateOnlyOnce){
	var queryStr = getQueryParameters();
	if(typeof(fields)=='undefined')fields = init_fields();
	var itemAlreadyRate = false;
	var thisId = queryStr.ID;
	var currentRatingObj = getRatingDispForm(thisId);
	if(currentRatingObj[thisId]==undefined){
		rPos = 0;
		rNeg = 0;
	}else{
		// Previously rated by current user
		if(rateOnlyOnce && currentRatingObj[thisId]['ratedByMe']==true){
			itemAlreadyRate = true;
		}
		rPos = currentRatingObj[thisId]['Plus'];
		rNeg = currentRatingObj[thisId]['Minus'];
	}
	// Rated in this session
	if(sessvars[thisListsGuid+thisId]==1 && currentRatingObj!=false){
		itemAlreadyRate = true;
	}
	var thisTd = $(fields[FieldInternalName]).find('.ms-formbody');
	var str = "<div style='color:gray'>";
	str += "<img ";
	if(!itemAlreadyRate){
		str += "onclick='javascript:rateMe("up","+thisId+")' title='Rate Up' ";
		str += "style='vertical-align:middle;cursor:pointer' ";
	}else{
		str += "title='You have already rated this item "+currentRatingObj[thisId]['ratedByMeVal']+"' ";
		str += "style='vertical-align:middle;cursor:no-drop' ";
	}
	str += "src='/_layouts/images/arrupi.gif'>";
	str += "<span style='font-weight:bold;' id='rateUp_"+thisId+"'>"+rPos+"</span>";
	str += "<img ";
	if(!itemAlreadyRate){
		str += "onclick='javascript:rateMe("down","+thisId+")' title='Rate Down' ";
		str += "style='vertical-align:middle;cursor:pointer' ";
	}else{
		str += "title='You have already rated this item "+currentRatingObj[thisId]['ratedByMeVal']+"' ";
		str += "style='vertical-align:middle;cursor:no-drop' ";
	}
	str += "src='/_layouts/images/arrdowni.gif'>";
	str += "<span style='font-weight:bold;' id='rateDown_"+thisId+"'>"+rNeg+"</span>";
	str += "</div>";
	// Write HTML
	thisTd.html(str);
}

function getRatingDispForm(itemID){
// Path to webservices
wsBaseUrl = L_Menu_BaseUrl + '/_vti_bin/';
var query = "<Where><And><Eq><FieldRef Name='ListGuid' /><Value Type='Text'>"+thisListsGuid+"</Value></Eq>"+
			"<Eq><FieldRef Name='ItemID' /><Value Type='Text'>"+itemID+"</Value></Eq></And></Where>";
var rating = queryItems('RatingForSharePoint',query,['Plus','Minus','ItemID','Author']);
	if(rating.count==-1){
		alert("An error occured in the query:n"+query);
	}else if(rating.count>0){
	ratingObj = {};
		$.each(rating.items,function(i,item){
			var authorIdRaw = item['Author'];
			var authorId = authorIdRaw.substring(0,authorIdRaw.indexOf(';#'));
			var plusVal = item['Plus'];
			var minusVal = item['Minus'];
			if(plusVal==null)plusVal=0;
			if(minusVal==null)minusVal=0;
			if(ratingObj[item['ItemID']]==undefined){
				ratingObj[item['ItemID']]={'Plus':parseInt(plusVal),'Minus':parseInt(minusVal)};
			}else{
				ratingObj[item['ItemID']]['Plus']+=parseInt(plusVal);
				ratingObj[item['ItemID']]['Minus']+=parseInt(minusVal);
			}
			// Rated by current user
			if(_spUserId==authorId){
				ratingObj[item['ItemID']]['ratedByMe']=true;
				if(item['Plus']>0){
					ratingObj[item['ItemID']]['ratedByMeVal']="+1";
				}else{
					ratingObj[item['ItemID']]['ratedByMeVal']="-1";
				}
			}
		});
		return ratingObj;
	}else{
		return false;
	}
}

/************************************************************
*********************** Shared Code ***********************
************************************************************/
function rateMe(upORdown,id){
if(typeof(ctx)=='object'){
	var listGuid=ctx.listName;
	var listTitle = $.trim($("td.ms-pagetitle").text());
}else{
	var listGuid=thisListsGuid;
	var listTitle = $.trim($("td.ms-pagetitle a").text());
}
// Only rate item if not already rated in this session
if(sessvars[listGuid+id]==undefined){
	plus='';
	minus='';
	if(upORdown=='up'){
		sessvars[listGuid+id]=1;
			currVal = parseInt($("#rateUp_"+id).text());
			$("#rateUp_"+id).text(currVal+1)
				.prev().css({'background-color':'#C5E3BF'})
				.parent().find('img').attr({'onclick':'','title':'Rated +1'});
			// Prepare for writing rating
			plus=1;
	}else{
		sessvars[listGuid+id]=1;
		currVal = parseInt($("#rateDown_"+id).text());
		$("#rateDown_"+id).text(currVal+1)
			//.parent().css({'background-color':'#FFE4E1'})
			.prev().css({'background-color':'#FFE4E1'})
			.parent().find('img').attr({'onclick':'','title':'Rated -1'});
		// Prepare for writing rating
		minus=1;
	}

		// Get url
		var urlDir = location.pathname;

		// Path to webservices
		wsBaseUrl = L_Menu_BaseUrl + '/_vti_bin/';
		// Add item
		var res = addItem('RatingForSharePoint',
							{'Title':"Rating for: " + listTitle,
							'Plus':plus,
							'Minus':minus,
							'ListUrl':urlDir,
							'ListGuid':listGuid,
							'ListName':listTitle,
							'ItemID':id});
	}
}

// Attaches a call to the function to the "expand grouped elements function" for it to function in grouped listview's
function ExpGroupRenderData(htmlToRender, groupName, isLoaded){
	var tbody=document.getElementById("tbod"+groupName+"_");
	var wrapDiv=document.createElement("DIV");
	wrapDiv.innerHTML="<TABLE><TBODY id="tbod"+groupName+"_" isLoaded=""+isLoaded+"">"+htmlToRender+"</TBODY></TABLE>";
	tbody.parentNode.replaceChild(wrapDiv.firstChild.firstChild,tbody);
ratingForSharePoint();
}

// Function to separate each url search string parameters
function getQueryParameters(){
qObj = {};
var urlSearch = window.location.search;
	if(urlSearch.length>0){
		var qpart = urlSearch.substring(1).split('&');
		$.each(qpart,function(i,item){
			var splitAgain = item.split('=');
			qObj[splitAgain[0]] = splitAgain[1];
		});
	}
return qObj;
}

function init_fields(){
var res = {};
$("td.ms-formbody").each(function(){
if($(this).html().indexOf('FieldInternalName="')<0) return;
var start = $(this).html().indexOf('FieldInternalName="')+19;
var stopp = $(this).html().indexOf('FieldType="')-7;
var nm = $(this).html().substring(start,stopp);
res[nm] = this.parentNode;
});
return res;
}

Save as “RatingForSharePoint.js”, mind the file extension, and upload to the scriptlibrary as shown above.

Ask is something is unclear, and please report any bugs.

Regards
Alexander

Headings for SharePoint forms – another method

12.10.2011 Fixed a bug in the description for how to address the headings by name in the fields object.


20.06.2011 Fixed a bug with Firefox. The function “init_fields()” in the code for the file “BuildHeadingsFromArray.js” is replaced with “init_field_v2()”.

04.03.2010 Small update to the function “buildHeadingsFromArray(arr)” to skip “wrong FieldInternalNames”. Added padding-Left option.

I have previously shown a method for creating headings in a SharePoint form based on a single line text field

Here is another method that creates the headings without having to add a “placeholder” in the form.

With this “headings script” you can add a description to the field. This description can contain text or HTML (links, images etc):
IMG

As always we start like this:
Create a document library to hold your scripts (or a folder on the root created in SharePoint Designer). In this example i have made a document library with a relative URL of “/test/English/Javascript” (a sub site named “test” with a sub site named “English” with a document library named “Javascript”):
IMG

The jQuery-library is found here. The pictures and the sourcecode refers to jquery-1.3.2.min. If you download another version, be sure to update the script reference in the sourcecode.

The sourcecode for the file “BuildHeadingsFromArray.js” is found below.

Add this code to a CEWP below the list form in NewForm, DispForm and EditForm:

<script type="text/javascript" src="/test/English/Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/BuildHeadingsFromArray.js"></script>
<script type="text/javascript">
arrOfHeadings = [{"headingText":"This is a heading",				  
	"insertBefore":"Dummy2",
	"fontSize":"17",
	"fontWeight":"bold",
	"fontColor":"black",
	"paddingTop":"10",
	"paddingBottom":"2",
	"paddingLeft":"2",
	"descriptionText":"This description can contain text or HTML, like this link: <a href='https://spjsblog.com' target='_blank'>SharePoint JavaScripts</a> that opens in a new window.",
	"descrFontSize":"9",
	"descrFontColor":"black",
	"descrPaddingTop":"0",
	"descrPaddingBottom":"5"},	
	{"headingText":"This is a red heading",				  
	"insertBefore":"Dummy4",
	"fontSize":"17",
	"fontWeight":"bold",
	"fontColor":"#EE2C2C",
	"paddingTop":"10",
	"paddingBottom":"5",
	"paddingLeft":"2"}];
				  
buildHeadingsFromArray(arrOfHeadings);
</script>

Read here how to add a CEWP to the NewForm, DispForm or EditForm, and how to find the FieldInternalName of your columns.

You build the headings by creating an array of objects containing the various arguments to the script:

  • headingText: The actual heading.
  • insertBefore: FieldInternalName of the field to add the heading to.
  • fontSize: Size in pixels.
  • fontWeight: “normal”, “bold” etc.
  • strong>fontColor: Color name or hex value.
  • paddingTop: Padding in pixels.
  • paddingBottom: Padding in pixels.
  • descriptionText: The description test – leave blank if no description is required.
  • descrFontSize: Size in pixels.
  • descrFontColor: Color name or hex value.
  • descrPaddingTop: Padding in pixels.
  • descrPaddingBottom: Padding in pixels.

When the script to build the headings is executed, all the headings created are added to the “fields” object, and can be referred like any other field like this:
Heading before a field:
$(fields[“headingBefore_FieldInternalName of the field to add the heading to“])
Heading after a field:
$(fields[“headingAfter_FieldInternalName of the field to add the heading to“])
The sourcecode for the file “BuildHeadingsFromArray.js” looks like this:

/* Build headings from array
 * -----------------------------
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * v1.4
 * LastMod 20.06.2011
 * -----------------------------
 * Include reference to:
	jquery - http://jquery.com
	BuildHeadingsFromArray.js - This file
 * -----------------------------
 Call form CEWP below list form in NewForm, DispForm or EditForm like this:
	<script type="text/javascript" src="/test/English/Javascript/jquery-1.3.2.min.js"></script>
	<script type="text/javascript" src="/test/English/Javascript/BuildHeadingsFromArray.js"></script>
	<script type="text/javascript">
	arrOfHeadings = [{"headingText":"This is a heading",
					  "insertBefore":"Dummy2",
					  "insertAfter":"",
					  "fontSize":"17",
					  "fontWeight":"bold",
					  "fontColor":"black",
					  "padding":"10 2 5 2",
					  "descriptionText":"This is the description This is the description This is the description",
					  "descrFontSize":"9",
					  "descrFontColor":"black",
					  "descrPadding":"0 0 0 0"},
					  {"headingText":"This is another heading",
					  "insertBefore":"Dummy4",
					  "insertAfter":"",
					  "fontSize":"17",
					  "fontWeight":"bold",
					  "fontColor":"black",
					  "padding":"10 2 5 2"}];

	buildHeadingsFromArray(arrOfHeadings);
	</script>
*/

function buildHeadingsFromArray(arr){
if(typeof(fields)=='undefined')fields = init_fields_v2();
	$.each(arr,function(i,item){
	// Does the field exist?
	if(fields[item['insertBefore']]==undefined && fields[item['insertAfter']]==undefined)return;
		// Build heading
		var str = "";
		str += "<tr><td colspan='2' class='ms-formbody' style='padding:0'>";
		str += "<div style='font-size:"+item['fontSize']+"px;color:"+item['fontColor']+";font-weight:"+item['fontWeight']+";padding:"+item['padding']+"'>";
		str += item['headingText']+"</div>";
		// Description
		if(item['descriptionText']!=undefined){
			str += "<div style='font-size:"+item['descrFontSize']+"px;color:"+item['descrFontColor']+";padding:"+item['descrPadding']+"'>";
			str += item['descriptionText']+"</div>";
		}
		str += "</td></tr>";
		if(item['insertBefore']!=''){		
			$(fields[item['insertBefore']]).before(str);
			// Add heading to fields object - refer as "heading_FieldInternalName"
			fields['headingBefore_'+item['insertBefore']]=$(fields[item['insertBefore']]).prev();
		}else if(item['insertAfter']!=''){
			$(fields[item['insertAfter']]).after(str);	
			// Add heading to fields object - refer as "heading_FieldInternalName"
			fields['headingAfter_'+item['insertAfter']]=$(fields[item['insertAfter']]).next();
		}		
	});
}

function init_fields_v2(){
	var res = {};
	$("td.ms-formbody").each(function(){
	var myMatch = $(this).html().match(/FieldName="(.+)"s+FieldInternalName="(.+)"s+FieldType="(.+)"s+/);	
		if(myMatch!=null){
			// Display name
			var disp = myMatch[1];
			// FieldInternalName
			var fin = myMatch[2];
			// FieldType
			var type = myMatch[3];
			if(type=='SPFieldNote'){
				if($(this).find('script').length>0){
					type=type+"_HTML";
				}
			}
			if(type=='SPFieldLookup'){
				if($(this).find('input').length>0){
					type=type+"_Input";
				}
			}
			// Build object
			res[fin] = this.parentNode;
			$(res[fin]).attr('FieldDispName',disp);
			$(res[fin]).attr('FieldType',type);
		}		
	});
	return res;
}

Save as “BuildHeadingsFromArray.js”, mind the file extension, and upload to the scriptlibrary as shown above.

Ask if something is unclear.

Regards
Alexander

Display information from another list based on a lookup column connection

16.10.2013 New version: https://spjsblog.com/2013/10/16/display-information-from-another-list-based-on-a-lookup-column-connection-updated-version/

23.05.2010 Updated to fix hyperlink columns (splits the hyperlink by the first “, ” to separate URL and description).

20.05.2010 Updated to support hyperlink columns formatted as hyperlink and hiding of empty “rows”.

26.02.2010 Updated to support multiple lookup columns.


Here is is an example on how to display information from another list based on a lookup column connection.

You have a single choice lookup column connection to another list. When selecting a value from the lookup column, the script pulls the information from the “lookup source” and displays it below the lookup column.
IMG
As always we start like this:
Create a document library to hold your scripts (or a folder on the root created in SharePoint Designer). In this example i have made a document library with a relative URL of “/test/English/Javascript” (a sub site named “test” with a sub site named “English” with a document library named “Javascript”):
IMG

The jQuery-library is found here. The pictures and the sourcecode refers to jquery-1.3.2.min. If you download another version, be sure to update the script reference in the sourcecode.

The scripts “interaction.js” and “stringBuffer.js” is created by Erucy and published on CodePlex.

The sourcecode for the file “PullInformationFromConnectedList.js” is found below.

Add a CEWP below the list form in NewForm or EditForm, and insert this code:

<script type="text/javascript" src="../../Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="../../Javascript/interaction.js"></script>
<script type="text/javascript" src="../../Javascript/stringBuffer.js"></script>
<script type="text/javascript" src="../../Javascript/PullInformationFromConnectedList.js"></script>
<script type="text/javascript">
// Init all fields
fields = init_fields();
/* Object containing all arguments for the function
 * "arrFinAndDispName" is an array on format "FieldInternalName|Display name" from the list the lookup is pulling information from
 * "ListGuid" is the list Guid or the displayName of the list the lookup is pulling information from
 * "LookupFIN" id the FieldInternalName of the lookup column.
*/
var argumentObj = {'arrFinAndDispName':['Title|Element title',
					'TextField1|My text field 1',
					'TextField2|My text field 2',
					'TextField3|My text field 3',
					'Responsible|Responsible',
					'RichText|Rich text multi line'],
					'ListGuid':'405EC50E-FAF7-4473-8D50-F9E725BEAA9B',
					'LookupFIN':'Lookup'};

init_displayInfo(argumentObj);
</script>

You must change the list Guid of the “target list” to match your list, the “arrOfFieldsToReturn” to match your fields and the “Lookup column” FieldInternalName.

To use for multiple lookup columns, just build another “argumentObj”, and call the function “init_displayInfo” again with the new “argumentObj”.

Read here how to add a CEWP to the NewForm, DispForm or EditForm, how to find the list Guid of your list, and how to find the FieldInternalName of your columns.

The sourcecode for the file “PullInformationFromConnectedList.js” looks like this:

/* Display information from another list based on a lookup column connection
 * ----------------------------------------------------
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * https://spjsblog.com
 * Copyright (c) 2009-2010 Alexander Bautz (Licensed under the MIT X11 License)
 * Version: 1.3
 * LastMod: 23.05.2010
 * LastChange: Updated the hyperlink handling (splits the hyperlink by the first ", " to separate URL and description
 * ----------------------------------------------------
 * Must include reference to:
	jQuery - http://jQuery.com
	interaction.js and stringBuffer.js - http://spjslib.codeplex.com
*/

function init_displayInfo(argObj){
if(typeof(fields)=='undefined')fields = init_fields();
// On load - For EditForm or for page refresh on formvalidation
var inpHidID = $(fields[argObj['LookupFIN']]).find('input').attr('optHid');
var selID = $("*[id='"+inpHidID+"']").val();
displayInfo(selID,argObj);

// Bind events to the selection of elements
	if($(fields[argObj['LookupFIN']]).find('img').length==0){
	 // Lookup when it contains less than 20 elements
		$(fields[argObj['LookupFIN']]).find('select').change(function(){
			var selID = $(this).val();
			displayInfo(selID,argObj);
		});		
	}else{
	// Lookup when it contains more than 20 elements
		// Enter the lookup value in the input field	
		$(fields[argObj['LookupFIN']]).find('input').keydown(function(e){
			if(e.keyCode==13){
				var inpHidID = $(this).parents('tr:first').find('input').attr('optHid');
				var selID = $("*[id='"+inpHidID+"']").val();
				displayInfo(selID,argObj);
			}			
		});
		
		// Select from the dropdown
		$(fields[argObj['LookupFIN']]).find("img").click(function(){
			// The "options container" is shared between all lookup column
			$("*[id='_Select']").bind("dblclick keydown", function(e){
				var selID = $(this).val();
				displayInfo(selID,argObj);
			});
		});		
	}
}

function displayInfo(selectedID,argObj){
	var strRaw = getListItemFromLookup(selectedID,argObj);
	// Remove existing preview
	$("#customListAbstract_"+argObj['LookupFIN']).remove();
	str = "";
	// Display the selected element
	if(strRaw!=false){
		$.each(strRaw,function(fin,val){
			if(val!=' '){
				if(val.indexOf('http')==0){
					var part_1 = val.substring(0,val.indexOf(', '));
					var part_2 = val.substring(val.indexOf(', ')+2);
					val = "<a title='Opens in a new window' href='"+part_1+"' target='_blank'>"+part_2+"</a>";
				}
				str += "<tr style='font-size:10px;color:gray'>",
				str += "<td valign='top' width='200px' style='border-bottom:1px silver solid;border-right:1px silver solid;padding:2'>"+fin+"</td>";
				str += "<td valign='top' style='padding:2;border-bottom:1px silver solid'>"+val+"</td>";
				str += "</tr>";
			}
		});
		str = "<tr id='customListAbstract_"+argObj['LookupFIN']+"'>"+
			  "<td colspan='2' style='padding:5 10 5 10'>" +
			  "<table width='580' cellspacing='0' cellpadding='0' style='border-top:1px silver solid'>"+str+"</table>" +
			  "</td></tr>"
	}
	// Insert the preview below the lookup column
	$(fields[argObj['LookupFIN']]).after(str);
}

function getListItemFromLookup(LookupID,argObj){
var arrFin = [];
var arrDispName = [];
// Split the array in separate arrays for InternalName and DisplayName
$.each(argObj['arrFinAndDispName'],function(i,item){
	split = item.split('|');
	arrFin.push(split[0]);
	arrDispName.push(split[1]);
});
	// Get the correct list item
	wsBaseUrl = L_Menu_BaseUrl + '/_vti_bin/'; // Change this path if the list is not in the current site
	var item = getItemById(argObj['ListGuid'],LookupID,arrFin);
	if(item!=null){
		var ret = {};
		$.each(arrFin,function(i,fin){
			var thisVal = item[fin];
			if(thisVal==null){
				thisVal=' ';
			}else if(thisVal.indexOf(';#')>0){
				thisVal=thisVal.substring(thisVal.indexOf(';#')+2);
			}
			ret[arrDispName[i]]=thisVal;
		});
		return ret;
	}else{
		return false;
	}
}

function init_fields(){
var res = {};
$("td.ms-formbody").each(function(){
if($(this).html().indexOf('FieldInternalName="')<0) return; 
var start = $(this).html().indexOf('FieldInternalName="')+19;
var stopp = $(this).html().indexOf('FieldType="')-7; 
var nm = $(this).html().substring(start,stopp);
res[nm] = this.parentNode;
});
return res;
}

Save as “PullInformationFromConnectedList.js”, mind the file extension, and upload to the script library as shown above.

Ask is anything is unclear.

Regards
Alexander

Add “Invert”, “Check all” and “Uncheck all” to a multichoice checkbox column or the entire form

Change log
October 1, 2014
Updated the code example to support newer versions of jQuery.

I got this request:

Hi Alexander:
Further to your Multiple Choice Checkbox solution, do you know of a way to add a “Select All” to all checkboxes on an entire form?

Thanks-
Charlie Epes

Here is a possible solution
IMG


Add this code to a CEWP below the form in NewForm or EditForm: Alter the reference to jQuery if necessary.

<script type="text/javascript" src="/Scripts/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
/* Add "Invert", "Check all" and "Uncheck all" to a multichoice checkbox column, or a Yes/No column
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * https://spjsblog.com
 * v1.1
 * LastMod: 01.10.2014
 *	
*/
// Initialt all fields
var fields = init_fields_v2();

// To insert a control above a specific field call with the fieldinternalname as argument
init_toggleAll('MyMultiChoice');
// To insert a control above the formtable and control all checkboxes in the form, call with no argument
init_toggleAll();

function init_toggleAll(FieldInternalNameOrEmpty){
	var str = [], elm;
	str.push("<span title='Invert selection' style='cursor:pointer' onclick='javascript:toggleAll($(this),0)'>Invert</span> | ");
	str.push("<span title='Check all' style='cursor:pointer' onclick='javascript:toggleAll($(this),1)'>All</span> | ");
	str.push("<span title='Uncheck all' style='cursor:pointer' onclick='javascript:toggleAll($(this),2)'>None</span>");
	if(fields[FieldInternalNameOrEmpty]===undefined){
		elm = $("table.ms-formtable");
		elm.before("<div style='font-size:10px;padding-top:5px'>"+str.join("")+"</div>");
	}else{
		elm = $(fields[FieldInternalNameOrEmpty]).find('.ms-formbody');
		elm.prepend("<div style='font-size:10px'>"+str.join("")+"</div>");
	}
}

function toggleAll(elm,action){
	elm.parents("td:first").find('input:checkbox').each(function(){
		if(action === 0){
			if($(this).prop('checked')==false){
				$(this).prop('checked',true);
			}else{
				$(this).prop('checked',false);
			}
		}else if(action === 1){
			$(this).prop('checked',true);
		}else if(action === 2){
			$(this).prop('checked',false);
		}
	});
}

function init_fields_v2(){
	var res = {};
	$("td.ms-formbody").each(function(){
	var myMatch = $(this).html().match(/FieldName="(.+)"\s+FieldInternalName="(.+)"\s+FieldType="(.+)"\s+/);	
		if(myMatch!=null){
			// Display name
			var disp = myMatch[1];
			// FieldInternalName
			var fin = myMatch[2];
			// FieldType
			var type = myMatch[3];
			if(type=='SPFieldNote'){
				if($(this).find('script').length>0){
					type=type+"_HTML";
				}else if($(this).find("div[id$='TextField_inplacerte']").length>0){
					type=type+"_EHTML";
				}				
			}
			if(type==="SPFieldLookup"){
				if($(this).find("input").length>0){
					type=type+"_Input";
				}
			}
			// HTML Calc
			if(type==='SPFieldCalculated' && $(this).text().match(/(<([^>]+)>)/ig)!==null){
				$(this).html($(this).text());
			}		
			// Build object
			res[fin] = this.parentNode;
			$(res[fin]).attr('FieldDispName',disp);
			$(res[fin]).attr('FieldType',type);
		}		
	});
	return res;
}
</script>

Other similar articles:

Regards
Alexander

Multiple default values in a column of type “Checkboxes”

I got this request from Larry:

choice – Multiple select, check boxes, is there a way to have multiple default values. I may want the same 3 items to always be selected. by default SP only allows one option. This field for 90% may need those 3 requests. Can it be done?


Add this code to a CEWP below the form in NewForm or EditForm: Alter the reference to jQuery as needed.

&lt;script type=&quot;text/javascript&quot; src=&quot;../../Javascript/jquery-1.3.2.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
/* Multiple default values in a column of type &quot;Checkboxes (allow multiple selections)&quot;
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * https://spjsblog.com
 * v1.0
 * LastMod: 22.02.2010
 *	
 Sets the default value of a column of type &quot;Checkboxes (allow multiple selections)&quot;,
 by passing the FieldInternalName of the SharePoint-field with an array of values to prefill.
*/
fields = init_fields();
// Define the array if values
var myArr = ['Choice 4','Choice 9'];
// Call the function with the FieldInternalName of the field and the array.
setMultiSelectDefaultValues('MyMultiChoice',myArr);

function setMultiSelectDefaultValues(FieldInternalName,arrOfValues){
	$(fields[FieldInternalName]).find('input:checkbox').each(function(){
		var thisText = $(this).next().text();
		if($.inArray(thisText,arrOfValues)&gt;-1){
			$(this).attr('checked',true);
		}
	});
}

function init_fields(){
  var res = {};
  $(&quot;td.ms-formbody&quot;).each(function(){
	  if($(this).html().indexOf('FieldInternalName=&quot;')&lt;0) return;	
	  var start = $(this).html().indexOf('FieldInternalName=&quot;')+19;
	  var stopp = $(this).html().indexOf('FieldType=&quot;')-7; 
	  var nm = $(this).html().substring(start,stopp);
	  res[nm] = this.parentNode;
  });
  return res;
}
&lt;/script&gt;

You also might want to take a look at this one:
Limit number of allowed selections in Checkboxes choice

Regards
Alexander

Multi line text field in list view: Shorten text and add hovereffect to view full text

11.08.2010 Updated description to of the parameter “FieldInternalName”. Use “DisplayName” if the multiline field is of type rich or enhanced rich test.


I got this request from ronajon:

hi Alexander,
i accidently stumbled on your great blog search for a way to modify my lsitview with javascript.

here’s what i would like to accomplish:
i have this allitems view with multiple columns. One of these colums is of the multi lines of text.
When i start editing my items my multiline column cell strats growing in size due to a point that i can only see one item in my screen and need to scroll down to see other items in the list.

Is there a way to limit the number of characters in the multi line column (named “Voortgang en resultaat”) to show less characters: preferably one line of text or text up until some splitting character?

thanks,
ronajon


The text is limited to 100 characters, but when hovered, it shows the full text:
IMG

As always we start like this:
Create a document library to hold your scripts (or a folder on the root created in SharePoint Designer). In this example i have made a document library with a relative URL of “/test/English/Javascript” (a sub site named “test” with a sub site named “English” with a document library named “Javascript”):
IMG

The jQuery-library is found here. The pictures and the sourcecode refers to jquery-1.3.2.min. If you download another version, be sure to update the script reference in the sourcecode.

The code for the file “LimitMultilineTextInView.js” is found below.

This will work in standard views and in grouped views, but has not been adapted to work with “Boxed” views.

Add a CEWP below the list view and add this code:

<script src="/test/English/Javascript/jquery-1.3.2.min.js" type="text/javascript"></script>
<script src="/test/English/Javascript/LimitMultilineTextInView.js" type="text/javascript"></script>
<script type="text/javascript">
// Shows the first 100 characters in the text
	limitMultiLineText('MultilineText',100);
// Shows the text 'Hover to see content' in stead of the actual text
	//limitMultiLineText('MultilineText','','Hover to see content');
</script>

Parameters explained:

  • FieldInternalName: The “FieldInternalName” of the field containing the multi line text. Use DisplayName if the multiline field is of type rich or enhanced rich text. (how to find the FieldInternalName)
  • initialLength: Limit the initial displayed text to this number of characters. This argument is overridden by the next, if supplied.
  • inPlaceHoverText: If set, this argument will override the previous, and add a “inPlace” text that can be hovered to view the full text.

When hovered there are a delay for 650 milliseconds to prevent flickering when you move the mouse rapidly over multiple cells.

The code for the file “LimitMultilineTextInView.js” looks like this:

/* Limit the length of the text in a multi line text field in a list view
* Created by Alexander Bautz
* alexander.bautz@gmail.com
* https://spjsblog.com
* v1.0
* LastMod: 21.02.2010
* ---------------------------------------------
* Requirements:
Include reference to jquery - http://jquery.com
* ---------------------------------------------
*
Call from a CEWP below list view like this:
<script src="/test/English/Javascript/jquery-1.3.2.min.js" type="text/javascript"></script>
<script src="/test/English/Javascript/LimitMultilineTextInView.js" type="text/javascript"></script>
<script type="text/javascript">
	// Shows the first 100 characters in the text
		limitMultiLineText('MultilineText',100);
	// Shows the text 'Hover to see content' in stead of the actual text
		//limitMultiLineText('MultilineText','','Hover to see content');
	
</script>
*/

function limitMultiLineText(FieldInternalName,initialLength,inPlaceHoverText){
if(typeof(FieldInternalName)!='undefined'){
intName = FieldInternalName;
initLength = initialLength;
inPlaceText = inPlaceHoverText;
$(".ms-viewheadertr th.ms-vh2-nograd").each(function(){
if($(this).text()==intName){
colIndex = $(this).attr('cellIndex');
}
});
}

$("table.ms-listviewtable tbody:not([id^='aggr']) tr:has(td.ms-vb2) >td[cellIndex=" + colIndex + "][beenthere!=1]").each(function(){
$(this).attr('beenthere',1);
var thisTd = $(this);
if(inPlaceText!='' && inPlaceText!=undefined){
var teaserText = inPlaceText;
}else{
var teaserText = thisTd.text().substring(0,initLength);
}
thisTd.wrapInner("<div style='background-color: white; border: thin silver ridge; padding: 4px; display: none;'></div>")
.prepend("<span style="cursor: default;">"+teaserText+"...</span>")
.hover(function(){
thisTd.addClass('dummyHoverClass ms-dialogSelectedRow');
setTimeout(function(){
if(thisTd.hasClass('dummyHoverClass')){
var offset = thisTd.offset();
var tdWidth = thisTd.width();
thisTd.find('div:first')
.css({'position':'absolute',
'top':offset.top,
'left':offset.left,
'width':tdWidth})
.fadeIn(250)
.prev()
.hide();
}
},650);
},function(){
if(thisTd.hasClass('dummyHoverClass')){
thisTd.removeClass('dummyHoverClass ms-dialogSelectedRow');
thisTd.find('div:first').stop(true, true).fadeOut(100).prev().show();
}
});
});
}

// Attaches a call to the function "limitMultiLineText()" to the "expand grouped elements function" for it to function in grouped listview's
function ExpGroupRenderData(d,a,e){
ULSA13:;
var c=document.getElementById("tbod"+a+"_"),b=document.createElement("DIV"),f=a.split("-");
b.innerHTML='<TABLE><TBODY id="tbod'+a+'_" isLoaded="'+e+'">'+d+"</TBODY></TABLE>";
c.parentNode.replaceChild(b.firstChild.firstChild,c);
limitMultiLineText();
}

Save the file as “LimitMultilineTextInView.js”, mind the file extension, and upload to the scriptlibrary as shown above.

Enjoy!
Alexander

Hit counter for SharePoint

28.05.2011 I have redone this solution to use a star-rating in stead of the simple “like” button. You find the new version here


01.11.2010 Redone the scripts and added support for rating individual items in a list – for example in “Dispform” in a blog:
IMG

The solution counts “Hits” and “Likes”.


Create a document library to hold your scripts

Or a folder on the root created in SharePoint Designer). In this example i have made a document library with a relative URL of “/test/English/Blog/Scripts” (a sub site named “test” with a sub site named “English” with a subsite named “Blog” and a document library named “Scripts”).

When you refer the scripts in the CEWP, ensure that you point to the correct location of your scripts.

The jQuery-library is found here. The CEWP code refers to jquery-1.4.2.min. If you download another version, be sure to update the script reference in the CEWP.

The sessvars.js is created by Thomas Frank and can be found here

The sourcecode for the file “HitCounterForSharePoint.js” is found here

Create a list with the name “HitCounter”, and add these fields:

  • URL: Multiline plain text
  • User: Person or Group
  • ReferringURL: Multiline plain text
  • Like: Single line of text

You have to give all users write access to the list “HitCounter”.

Add a CEWP where you want this counter to appear, and add this code:

&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Blog/Scripts/jquery-1.4.2.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Blog/Scripts/sessvars.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Blog/Scripts/HitCounterForSharePoint.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
	hitCounter(true,true);
&lt;/script&gt;

Parameters:

  • oncePerSession: True to allow one “hit-count” per unique item per browser session.
  • isDispForm: If true, includes the ID of the item to allow individual counting of each item in a list.

Ask if something is unclear!

Regards
Alexander

Manipulating the Custom Send To Destination in document library with javascript

You all know that you can send a copy of a document from one document library to another by using the dropdown on the “Name” column and selecting “Send to > Other location”.

Some of you also know that you can add a predefined “send to location” under Document library settings > Advanced settings.

The irritating fact is that you can only add one custom location here.


Here is a method for setting this custom send to location by javascript – and being able to manipulate it for each view – or by a dropdown select.

To set the location for a view – put this code in a CEWP below the list view:

<script type="text/javascript" src="../../Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
// Name displayed on the link
ctx.SendToLocationName = "My custom send to location";
// The full url to the document library to send to - i used ctx.HttpRoot as it reflects the current root
ctx.SendToLocationUrl = ctx.HttpRoot + "/TestLibrary";
</script>

IMG

To have a dropdown select, use this code:

<script type="text/javascript" src="../../Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
// Define array of locations
var mySendToArr = ['<select location>|',
		 'Archive|http://www.mysendtolocation.com/Archive',
		 'Publish|http://www.mysendtolocation.com/Publish',
		 'AnotherPlace|http://www.mysendtolocation.com/AnotherPlace'];
			  	   
// Build the dropdown			  	   
var mySelect = $("<select id='myCustomSendToSelector'></select>");
$.each(mySendToArr,function(idx,item){
	var split = item.split('|');
	var opt = $("<option></option>");	
	opt.text(split[0]);
	opt.val(split[1]);
	mySelect.append(opt);
});

// Place the dropdown
$("#onetidPageTitle").append("<div style='font-size:10px;float:right;margin-top:-15px' id='insertMySendToSelectHere'>Send to location: </div>");
$("#insertMySendToSelectHere").append(mySelect);

// Add onchange
$("#myCustomSendToSelector").change(function(){
	var SendToLocationName = $(this).find('option:selected').text();
	var SendToLocationUrl = $(this).find('option:selected').val();
	if(SendToLocationUrl!=''){
		ctx.SendToLocationName = SendToLocationName;
		ctx.SendToLocationUrl = SendToLocationUrl;
	}else{
		ctx.SendToLocationName = "";
		ctx.SendToLocationUrl = "";
	}
});
</script>

This script adds a dropdown above the view selector like this:
IMG

Ask if anything is unclear!

Regards
Alexander