All posts by Alexander Bautz

Autocomplete for SharePoint people picker

26.03.2010 Updated code to be able to clear the selection It’s only the code for the file “AutocompleteForPeoplePicker.js” that has changed. Thanks to Steve for pointing out the bug.

This solution adds auto complete functionality to a standard SharePoint people picker.

This solution is built with the autocomplete widget from jQuery UI. The values are pulled from the user list based on a query. All users with an email address are available.

Limitations:

  • Single choice only
  • No filter against user group, all users are displayed

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

In addition to the above scripts, i have the jQuery UI 1.8 in a separate folder. See the CEWP code and point the links to your jQuery UI location.

The jQuery UI-library is found here. The pictures and the sourcecode refers to jquery-ui-1.8. The autocomplete widget is not found in previous releases.

The jQuery-library is found here. The pictures and the sourcecode refers to jquery-1.4.min. The autocomplete widget is not supported in previous releases.

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

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

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

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

<style type="text/css">
.ui-menu .ui-menu-item {
	font-size:xx-small;
}
</style>
<link type="text/css" href="/test/English/jQueryUI18/smoothness/jquery-ui-1.8.custom.css" rel="stylesheet" />
<script type="text/javascript" src="/test/English/Javascript/jquery-1.4.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/jQueryUI18/jquery-ui-1.8.custom.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/AutocompleteForPeoplePicker.js"></script>
<script type="text/javascript">
fields = init_fields();

// Find all users from userlist. Parameters "userListBaseUrl" and "userListGuid"
var allUsers = getUsers('','570D772F-0EAB-45A8-8C54-9CCD4EC6A0AF');

// Call with FieldInternalName of your people picker field(s)
$(document).ready(function(){
	peoplePickerAutoclomplete('MyPeoplePicker');
	peoplePickerAutoclomplete('AnotherPeoplePicker');	
});
</script>

Parameters explained:

  • userListBaseUrl: The base URL of the site the user list resides. If your site is in a managed path, it must reflect this managed path. If not, this parameter is most likely an empty string (“”)
  • userListGuid: The list Guid of the user list.

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

/* Add autocomplete functionality to a SharePoint people picker
 * -----------------------------
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * https://spjsblog.com
 * v1.0
 * LastMod: 24.03.2010
 * -----------------------------
 * Must include reference to jQuery 1.4, jQuery UI 1.8 and to the folloving scripts:
 * ----------------------------------------------------
 * interaction.js - http://spjslib.codeplex.com/
 * stringBuffer.js - http://spjslib.codeplex.com/
 * ----------------------------------------------------
*/

function peoplePickerAutoclomplete(FieldInternalName){
if(typeof(fields)=='undefined')fields = init_fields();

var myPicker = $(fields[FieldInternalName]);
if(myPicker.find('div.ms-inputuserfield:visible').length>0){
	var ie=true; // Internet Explorer
	var toFind = 'div.ms-inputuserfield';
	var inputStyle = "margin:-1 0 -1 0;height:18px;font-family:Verdana,sans-serif;font-size:8pt;width:100%;display:none";

}else{
	var ie=false; // Firefox
	var toFind = 'textarea:first';
	myPicker.find('textarea:first').css({'height':'18px'});
	var inputStyle = "margin:1 0 1 0;height:18px;font-family:Verdana,sans-serif;font-size:8pt;width:100%;display:none";
}
	myPicker.find(toFind)
		.before("<input hiddenval='' style='"+inputStyle+"' id='"+FieldInternalName+"'/>")
		.focus(function(){
			$(this).hide().prev().show().focus();
		});

	// Add autocomplete
	$("#"+FieldInternalName).autocomplete({
			source: allUsers,
			select: function(event, ui) {
				fillPicker(ie,myPicker,FieldInternalName,ui.item.writeBackValue,ui.item.value);				
				return false;
			}		
		}).blur(function(){
			var currVal = $(this).val();
			var prevVal = $(this).attr('hiddenval')
			if(currVal!=''&&currVal!=prevVal){
				$(this).val($(this).attr('hiddenval'))
			}else if(currVal==''){
				fillPicker(ie,myPicker,FieldInternalName,'','');	
			}
			$(this).hide().next().show();
	});	
}

function fillPicker(ie,field,fin,loginName,dispName){
	if(ie){
		// IE
		field.find('.ms-inputuserfield').html(loginName);
		$("#"+fin).val(dispName).attr('hiddenval',dispName);
		field.find('img:first').click();
	}else{
		// FF
		field.find("textarea:first").val(loginName);
		$("#"+fin).val(dispName).attr('hiddenval',dispName);
	}
}

function getUsers(userListBaseUrl,userListGuid){
	var query = "<Where><And><IsNotNull><FieldRef Name='EMail' /></IsNotNull>" +
				"<Eq><FieldRef Name='ContentType' /><Value Type='Text'>Person</Value></Eq></And></Where>" +
				"<OrderBy><FieldRef Name='Title' Ascending='TRUE'/></OrderBy>";
	wsBaseUrl = userListBaseUrl + '/_vti_bin/';	
	var res = queryItems(userListGuid,query,['ID','Title','Name','EMail','ContentType']); 
    var ret = [];
    $.each(res.items,function(idx,item){ 	
    	ret.push({label:item['Title']+"<br>"+item['EMail']+"<br>"+item['Name'],value:item['Title'],writeBackValue:item['Name'],desc:'Test'});	
    });
    return ret;    
}

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 “AutocompleteForPeoplePicker.js”, mind the file extension, and upload to the script library as shown above.

I will update the article on Edit date, single line text, number or boolean columns directly in list view based on this script to allow setting a people picker field directly in a list view.

Ask is anything is unclear.

Regards
Alexander

vLookup type rollup for SharePoint

02.03.2011 Updated the code for the file “vLookupForSharePoint.js” to v1.7.0

  • Add an “orderBy” option to sort the returned items by a FieldInternalName – See parameter descriptions below.
  • The dependencies upon interaction.js and stringBuffer.js has been eliminated.

10.06.2010 Updated the code for the file “vLookupForSharePoint.js” to fix some bugs.
This update includes:

  • Support for multiple webparts in one page
  • Bugfix: get listName in EditForm mode
  • Added option “DispFormRelURL” under “inQueryString” to provide current items relative DispForm URL
  • Handling multichoice values by replacing “;#” with “<br />”
  • Fixed bug with “newItemLink” if “linkBack” is not true
  • Added id tag for the “newItemLinkContainer” – to make hiding it possible.
  • Fixed bug when item has no “children” (newItemLink and inQueryString)
  • Fixed bug when matching on a calculated column

06.05.2010 Updated the code for the file “vLookupForSharePoint.js”.

This update includes:

  • Some small bugfixes
  • Added support for getting items connected by a multiLookup
  • Added createNewItem option by setting the parameter “newItemLink:true”
  • Added inQueryString option to include values from DispForm when creating new items using the “createNewItem” option
  • Added option to display vLookup connected items in EditForm
  • Localized for Norwegian, Swedish and English

01.04.2010 Small update to the file “vLookupForSharePoint.js”. I have modified the argument “hoverToView” to have separate settings for DispForm and for ListView. You must change the argument “hoverToView” to “hoverToViewDispForm” and “hoverToViewListView” in your calculated columns.


I have long thought of making a generic solution for pulling information from another list, kind of like you would do in Excel with the function vLookup. Here is my attempt to create just this. I’m fairly confident this solution will fill an empty space in many SharePointers hearts…

This solution features

  • Easy, generic interface to pull information from any list in current site or cross site
  • Concatenation of values from multiple items
  • Sum, average or count values from multiple items
  • Link back to filtered view of all matched items in “sum”, “avg” or “count” -mode, or to individual items in “concat” -mode
  • Direct link to documents
  • “Reverse lookup” on lookup columns – the “mother” item now has link back to the “children”.
  • And more…

The way this solution works is by using a calculated column to build a string with all the parameters like this:

This code matches the ID of the current item against a lookup column (the “child-list” has a lookup column named “ParentBug” targeting the “Mother-list” – what field the lookup is connected to is irrelevant as it is the ID we are looking for). This approach is a bit different than it will be for other columns as the ID is not accessible to a normal calculated column.

="listName:vLookupBugTrackerTasks|find:ID|findInCol:ParentBug|action:concat|linkBack:true|viewFields:Title#Title;TaskDescription#Task description;Deadline#Deadline"

This example matches the text in the “Title” column in one list against the “Title” column in another list.

="listName:vLookupBugTrackerTasks|find:"&Title&"|findInCol:Title|action:concat|linkBack:true|viewFields:Title#Title"

These are the available arguments:

  • listName: Name or GUID of the target list.
  • listBaseUrl: The base URL of the site the target list is located in. Defaults to current site is the argument is omitted.
  • find: The string to search for in the column specified as “findInCol” below. To use the current items ID (in case of a lookup connection), specify like this: “find:ID”.
  • findInCol: The FieldInternalName of the column to query against.
  • viewFields: “Array” of the fields of which to return a value for. Format: FieldInternalName1#DisplayName1. Separate multiple fields with semicolon.
  • action: “sum”, “avg”, “count” or “concat”.
  • sumOrAvgPrefix: A prefix in “sum” or “avg” -mode, like “$” for dollar.
  • sumOrAvgPostfix: As above, but postfix.
  • linkBack: true=Link back to item(s), false=no linkback. Default value: false
  • linkBackView: If in “sum”, “avg” or “count” -mode, set the target view name for the filtered result on “linkBack”. Defaults to “AllItems.aspx” if omitted.
  • hoverToViewListView: (In “concat” -mode) true=Displays a placeholder text that the user must hover over with the mouse to view the items, false=View items directly in list view. Default value: false
  • hoverToViewDispForm: (In “concat” -mode) true=Displays a placeholder text that the user must hover over with the mouse to view the items, false=View items directly in DispForm. Default value: false
  • hoverToViewEditForm: (In “concat” -mode) true=Displays a placeholder text that the user must hover over with the mouse to view the items, false=View items directly in DispForm. Default value: false
  • newItemLink: (In “concat” -mode) true=Displays a “Create new item” link. Default value: false
  • inQueryString: (In “concat” -mode) semicolon separated array of FieldInternalNames to include the value from in the queryString that is passed to the NewForm. This only applies if the above parameter is set to true. Default value: “”. You need another script in the target list to pull the parameters from the query string and write them to a field in NewForm
  • orderBy: New! A FieldInternalName to sort the returned items by. Set the parameter “orderBy” in the calculated column like this: orderBy:Title. To have the result ordered descending, append a hash behind the FieldInternalName like this: orderBy:Title#

These are the base arguments that are required:
‘listName’,’find’,’findInCol’,’action’,’viewFields’

Note: If your formula errors out, it most likely has to do with the string being to long. To overcome this problem, just concatenate the string like this:
…first part of the string her”&”and the rest here…


Example images:

List view with tasks pulled from tasklist
IMG

Hover over each item for “link back menu”. Click on a “link back” will take you to the item
IMG

hoverToViewListView:true – before hover:
IMG

hoverToViewListView:true – after hover:
IMG

“sum”, “avg” or “count” looks like this:
IMG

A click on a “link back” on items in “sum”,”avg” or “count” -mode will take you to a filtered list of all matched items.
IMG
The target list view is set in the parameter “linkBackView”.

DispForm with “newItemLink:true”:
IMG

The same item in EditForm:
IMG

When setting the parameter inQueryString like this “inQueryString:Title;ID”, the value from these fields are included in the querystring of the URL (click to enlarge the image):
IMG
You need another script in the target list to pull the parameters from the query string and write them to a field in NewForm. Look here for an example.

When the code is added to the listView and to DispForm/EditForm, you create a new “enhanced lookup column” by creating a new field of type “Calculated (calculation based on other columns)” with a FieldInternalName starting with “vLookup” (you can rename the column afterwards, it’s only the FieldInternalName that is important). All fields with a FieldInternalName starting with this text will be included. No need to specify the columns to include! (this is not true for EditForm though, see separate instructions). Note: the ID column must be in the view (but can be hidden in the script).

Here is the code

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”).

The jQuery-library is referred from Google, but if you prefer a local copy, it is found here. The pictures and the sourcecode refers to jquery-1.5.1.min. If you download another version, be sure to update the script reference in the sourcecode.

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

Read here how to add a CEWP to the DispForm or EditForm.

Add this code in a CEWP below the list form in DispForm:

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/vLookupForSharePoint.js"></script>
<script type="text/javascript">
  init_vLookupForSharePointDispForm();
</script>

Add this code in a CEWP below the list form in EditForm:

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/vLookupForSharePoint.js"></script>
<script type="text/javascript">
  // This is an array of objects. Add more fields by adding a new object to the array
  // The "insertHere" value can be "top", "bottom" or a FieldInternalName to append the returned data to
  init_vLookupForSharePointEditForm([{'FieldInternalName':'vLookupTasks','FieldDisplayName':'Tasks','insertHere':'BugDescription'}]);
</script>

The reason the EditForm code is different is that the calculated column is not available unless we query for it using a CAML query. The “insertHere” parameter is used to place the “new field”.

Add this code in a CEWP below the list view:

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/vLookupForSharePoint.js"></script>
<script type="text/javascript">
// The argument "true" sets the ID column to hidden
  init_vLookupForSharePointListView(true);
</script>

The code for the file “vLookupForSharePoint.js”:
download code

Upload the file to the scriptlibrary as described above.

If you find any bugs, please let me know!

Regards
Alexander

Filter Radio Buttons or Checkboxes based on selection in another field

Change log:

06.10.2010 Fixed a bug with unchecking hidden options when using a multi choice checkbox type column as “consumer” column (line 84 in the code). Thanks to Mike for finding the bug.

31.08.2010 Modified the code to hide the “consumer field” entirely if no items is visible.

16.07.2010 Updated the code to support checkboxes (allow multiple selections) in both “trigger” and “consumer” columns. I have also changed the logic from using the index of the option to use the actual text value.

15.03.2010 small update to the code to handle blank “triggervalue”. Thanks to Larry.


I got this request from Elstone:

Hello

I have two choice fields, 1 drop down and another is multiple radio buttons (6 values/radio button). This I want to implement on newform/editform

In dropdown I have 3 values i.e. Yes/No/Not Sure (selected by default).

I want to show/hide some of the radio buttons out of 6 radio buttons depending on condiion.

Let say
if user select “Yes”, then show radiobutton1 and radiobutton 3
If user select “No” , then show radiobutton2 and radiobutton 5
If user select “Not Sure” then show all the radio buttons

How can I do this?


IMG

IMG

This script will work for single value <select>, Radio Buttons and Checkboxes. The script will uncheck all hidden options, so if you flip the selection from “Yes” to “No” any selections made under “Yes” will be cleared.

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
Note: picture refers to jquery-1.3.2.min.js, but code uses jquery-1.4.2.min.js.

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

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

&lt;script type=&quot;text/javascript&quot; src=&quot;../../Javascript/jquery-1.4.2.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
// Make object of all TR
fields = init_fields_v2();

// Call function with FieldInternalName of triggerfield and targetfield
init_hideRadiobuttons('MyTriggerColumn','MyRadioButton');

function init_hideRadiobuttons(triggerColumnFIN,radioButtonFIN){
var type = 'single';
if($(fields[triggerColumnFIN]).find('input').length&gt;0)type = 'multi';
	var thisVal = [];
	switch(type){
	case 'single':
		// Onload
		thisVal.push($(fields[triggerColumnFIN]).find('option:selected').text());
		hideRadiobuttons(radioButtonFIN,thisVal);
		// Onchange
		$(fields[triggerColumnFIN]).find('select').change(function(){
		thisVal = [];
			thisVal.push($(this).find('option:selected').text());
			hideRadiobuttons(radioButtonFIN,thisVal);
		});
	break;
	case 'multi':	
		// Onload
		$(fields[triggerColumnFIN]).find('input').each(function(){
			if($(this).attr('checked')){
				thisVal.push($(this).next().text());
			}
		});
		hideRadiobuttons(radioButtonFIN,thisVal);			

		// Onclick
		$(fields[triggerColumnFIN]).find('input').click(function(){
		thisVal = [];
			$(fields[triggerColumnFIN]).find('input').each(function(){
				if($(this).attr('checked')){
					thisVal.push($(this).next().text());
				}
			});
			hideRadiobuttons(radioButtonFIN,thisVal);			
		});
		break;
	}
}

function hideRadiobuttons(FieldInternalName,arrOfValues){
var showArr = [];
	$.each(arrOfValues,function(i,val){
		switch(val){
			case 'Yes':
				showArr.push('Selected Yes - option 1',
							 'Selected Yes - option 2',
							 'Selected Yes - option 3');
			break;
			case 'No':
				showArr.push('Selected No - option 1',
							 'Selected No - option 2',
							 'Selected No - option 3');
			break;
			case 'Not Sure':
				showArr.push('Selected Yes - option 1',
							 'Selected Yes - option 2',
							 'Selected Yes - option 3',
							 'Selected No - option 1',
							 'Selected No - option 2',
							 'Selected No - option 3');
			break
		}
	});
	if(showArr.length==0){
		// Hide row
		$(fields[FieldInternalName]).hide();
	}else{
		// Unhide row
		$(fields[FieldInternalName]).show();
		// Show options
		$(fields[FieldInternalName]).find('label').each(function(){
			var thisVal = $(this).text();
			if($.inArray(thisVal,showArr)&gt;-1){
				$(this).parents('tr:first').show();
			}else{
				$(this).prev().attr('checked',false)
				$(this).parents('tr:first').hide();			
			}
		});
	}
}

/*
  LastMod: 07.05.2010
*/
function init_fields_v2(){
	var res = {};
	$(&quot;td.ms-formbody&quot;).each(function(){
	var myMatch = $(this).html().match(/FieldName=&quot;(.+)&quot;s+FieldInternalName=&quot;(.+)&quot;s+FieldType=&quot;(.+)&quot;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&gt;0){
					type=type+&quot;_HTML&quot;;
				}
			}
			if(type=='SPFieldLookup'){
				if($(this).find('input').length&gt;0){
					type=type+&quot;_Input&quot;;
				}
			}
			// Build object
			res[fin] = this.parentNode;
			res[fin].FieldDispName = disp;
			res[fin].FieldType = type;
		}		
	});
	return res;
}
&lt;/script&gt;

You must update the “cases” in the function “hideRadiobuttons” to match your setup.

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

Regards
Alexander

Add character or word count to SharePoint multi line plain text field and restrict input length

13.03.2011 Updated the code to handle pasting into the field by adding “blur” eventhandler. Referred jQuery from Google.


14.03.2010 Updated to count down from limit to 0 and color code the counter. Also merged the “Count characters” and the “Count words” functions to one. See new code and explanation below.

I got this request from Larry:

new request for you. Character/word counter for multiple line field to display below the field. Not general for all multiple lines, but setup in a way that can set fieldinternalnames in am arr. also can we add a character limit, so user can not enterany more text.

I have several character counters. cant get it on the form. I am also looking into adding it on the create field page. calculated fields can only accept about 1000 characters. would like a way to display the count on that page.

I cannot help with the “create new column page”, as it is a server side file, shared between all site collections running on this server.


IMG

Add a CEWP below your NewForm and EditForm and add this code:
Get the code here

Parameters explained:

  • FieldInternalName: FieldInternalName of the multi line plain text field.
  • countWords: true to count words, false to count characters.
  • limit: 0 for no limit and count up, a value bigger then 0 to set a limit and to count down.
  • colorCodeCounter: true to add orange/red coding when limit is approaching.
  • counterPrefix: The text to show before the counter.

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

Ask if anything is unclear
Alexander

Show active list filter above list view

I got this request:

Hi Alexander:
Another “is it possible?” question…

Is it possible to have a specific column’s filter choice appear in a CEWP that I would place above a list view?

Example: Filter the page by [Customer]
CWEP: would contain text + [Customer]

Thanks-

Charlie Epes


To pull the list filter from the URL and display it above the web part, put this code in a CEWP below the webpart (change the reference to jQuery if necessary):

&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/jquery-1.3.2.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
/* This code must be placed below the webpart it shall reflect */
// Get all querystring parameters
var queryString = getQueryParameters();

// Get all DisplayNames for the columnFilter
objFinDisp = {};
$(&quot;.ms-viewheadertr th&quot;).each(function(){
	objFinDisp[$(this).find('table:first').attr('name')] = $(this).find('table:first').attr('displayname');
});

// Loop trough and extract all querystring parameters that has &quot;Filter&quot; in it
myFilterStr = '';
$.each(queryString,function(param,val){
	if(param.indexOf('FilterField')==0 || param.indexOf('FilterValue')==0){
		// Switch the FieldInternalName for the DisplayName
		if(objFinDisp[val]!=undefined)val=objFinDisp[val];
		// Write the filter
		if(param.indexOf('FilterField')==0){
			myFilterStr += decodeURI(val)+&quot; = &quot;;
		}else{
			myFilterStr += decodeURI(val)+&quot;&lt;br&gt;&quot;;
		}
	}
});

// Put filter string in the top of the page
$(&quot;.ms-bodyareaframe&quot;).prepend(&quot;&lt;div&gt;&quot;+myFilterStr+&quot;&lt;/div&gt;&quot;);

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

Alexander

SharePoint form – Accordion in Tabs

This is a draft/example to keep Steve busy over the weekend 🙂 (see his request here).

To get anything out of this code, you have to read the following articles: Tabs in SharePoint form and Accordion in SharePoint form


Here is the code:

&lt;!-- Date field text size --&gt;
&lt;style type=&quot;text/css&quot;&gt;
.ms-dtinput,.ms-dttimeinput{
	font-size:0.7em;
}
&lt;/style&gt;
&lt;DIV id=&quot;tabs&quot;&gt;
	&lt;UL style=&quot;font-size:12px&quot;&gt;
		&lt;LI&gt;&lt;A href=&quot;#tabs-1&quot;&gt;Tab 1&lt;/A&gt;&lt;/LI&gt;
		&lt;LI&gt;&lt;A href=&quot;#tabs-2&quot;&gt;Tab 2&lt;/A&gt;&lt;/LI&gt;
		&lt;LI&gt;&lt;A href=&quot;#tabs-3&quot;&gt;Tab 3&lt;/A&gt;&lt;/LI&gt;
	&lt;/UL&gt;

	&lt;div id=&quot;tabs-1&quot;&gt;	
		&lt;div id=&quot;accordion-1&quot;&gt;	
			&lt;H3&gt;&lt;A href=&quot;#accordion-0&quot;&gt;Tab 1 Accordion 1&lt;/A&gt;&lt;/H3&gt;
			&lt;div&gt;&lt;table width=&quot;100%&quot; id=&quot;accTable-0&quot;&gt;&lt;/table&gt;&amp;nbsp;&lt;/div&gt;
			&lt;H3&gt;&lt;A href=&quot;#accordion-1&quot;&gt;Tab 1 Accordion 2&lt;/A&gt;&lt;/H3&gt;
			&lt;div&gt;&lt;table width=&quot;100%&quot; id=&quot;accTable-1&quot;&gt;&lt;/table&gt;&amp;nbsp;&lt;/div&gt;
			&lt;H3&gt;&lt;A href=&quot;#accordion-2&quot;&gt;Tab 1 Accordion 3&lt;/A&gt;&lt;/H3&gt;
			&lt;div&gt;&lt;table width=&quot;100%&quot; id=&quot;accTable-2&quot;&gt;&lt;/table&gt;&amp;nbsp;&lt;/div&gt;	
		&lt;/div&gt;	
	&lt;/div&gt;
	&lt;div id=&quot;tabs-2&quot;&gt;
		&lt;div id=&quot;accordion-2&quot;&gt;	
			&lt;H3&gt;&lt;A href=&quot;#accordion-3&quot;&gt;Tab 2 Accordion 1&lt;/A&gt;&lt;/H3&gt;
			&lt;div&gt;&lt;table width=&quot;100%&quot; id=&quot;accTable-3&quot;&gt;&lt;/table&gt;&amp;nbsp;&lt;/div&gt;
			&lt;H3&gt;&lt;A href=&quot;#accordion-4&quot;&gt;Tab 2 Accordion 2&lt;/A&gt;&lt;/H3&gt;
			&lt;div&gt;&lt;table width=&quot;100%&quot; id=&quot;accTable-4&quot;&gt;&lt;/table&gt;&amp;nbsp;&lt;/div&gt;
			&lt;H3&gt;&lt;A href=&quot;#accordion-5&quot;&gt;Tab 2 Accordion 3&lt;/A&gt;&lt;/H3&gt;
			&lt;div&gt;&lt;table width=&quot;100%&quot; id=&quot;accTable-5&quot;&gt;&lt;/table&gt;&amp;nbsp;&lt;/div&gt;	
		&lt;/div&gt;
	&lt;/div&gt;
	&lt;div id=&quot;tabs-3&quot;&gt;
		&lt;div id=&quot;accordion-3&quot;&gt;	
			&lt;H3&gt;&lt;A href=&quot;#accordion-6&quot;&gt;Tab 3 Accordion 1&lt;/A&gt;&lt;/H3&gt;
			&lt;div&gt;&lt;table width=&quot;100%&quot; id=&quot;accTable-6&quot;&gt;&lt;/table&gt;&amp;nbsp;&lt;/div&gt;
			&lt;H3&gt;&lt;A href=&quot;#accordion-7&quot;&gt;Tab 3 Accordion 2&lt;/A&gt;&lt;/H3&gt;
			&lt;div&gt;&lt;table width=&quot;100%&quot; id=&quot;accTable-7&quot;&gt;&lt;/table&gt;&amp;nbsp;&lt;/div&gt;
			&lt;H3&gt;&lt;A href=&quot;#accordion-8&quot;&gt;Tab 3 Accordion 3&lt;/A&gt;&lt;/H3&gt;
			&lt;div&gt;&lt;table width=&quot;100%&quot; id=&quot;accTable-8&quot;&gt;&lt;/table&gt;&amp;nbsp;&lt;/div&gt;	
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/DIV&gt;

&lt;link type=&quot;text/css&quot; href=&quot;/test/English/Javascript/jQueryUI/jquery-ui-1.7.2.custom.css&quot; rel=&quot;stylesheet&quot; /&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/jquery-1.3.2.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/jQueryUI/jquery-ui-1.7.2.custom.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
// Array of all fields - format: accordionID|FieldInternalName
arrTabAccordion = ['0|Title','0|Dummyfield1','0|Dummyfield2',
			'1|Dummyfield3','1|Dummyfield4','1|Dummyfield5',
			'2|Dummyfield6','2|Dummyfield7','2|Dummyfield8',
			'3|Dummyfield9','3|Dummyfield10','3|Dummyfield11',
			'4|Dummyfield12','4|Dummyfield13','4|Dummyfield14',
			'5|Dummyfield15','5|Dummyfield16','5|Dummyfield17',
			'6|Dummyfield18','6|Dummyfield19','6|Dummyfield20',
			'7|Dummyfield21','7|Dummyfield22','7|Dummyfield23',
			'8|Dummyfield24','8|Dummyfield25','8|Dummyfield26'];

// Initiate all the fields
fields = init_fields();

// Add the &quot;tabs&quot; to the formtable
$(&quot;#tabs&quot;).insertAfter('.ms-formtable').tabs();
// Add accordion
$(&quot;#accordion-1&quot;).accordion({autoHeight: false,animated: false});
$(&quot;#accordion-2&quot;).accordion({autoHeight: false,animated: false});
$(&quot;#accordion-3&quot;).accordion({autoHeight: false,animated: false});

// Loop trough all fields and move them to the right accordion section
$.each(arrTabAccordion,function(idx,item){
	var split = item.split('|');
	var accID = split[0];
	var fieldName = split[1];
	if(fields[fieldName]!=undefined){
		currField = $(fields[fieldName]);
		currField.appendTo('#accTable-'+accID);
	}
});

// Fix IE8 issue with zoom
$(&quot;.ui-accordion-content&quot;).css({'zoom':1,'padding':'0px'});

// function - to make &quot;object&quot; of all tr's in the form
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;

This is the same code, but added two fields to tab-2, outside the accordion:

&lt;!-- Date field text size --&gt;
&lt;style type=&quot;text/css&quot;&gt;
.ms-dtinput,.ms-dttimeinput{
	font-size:0.7em;
}
&lt;/style&gt;
&lt;DIV id=&quot;tabs&quot;&gt;
	&lt;UL style=&quot;font-size:12px&quot;&gt;
		&lt;LI&gt;&lt;A href=&quot;#tabs-1&quot;&gt;Tab 1&lt;/A&gt;&lt;/LI&gt;
		&lt;LI&gt;&lt;A href=&quot;#tabs-2&quot;&gt;Tab 2&lt;/A&gt;&lt;/LI&gt;
		&lt;LI&gt;&lt;A href=&quot;#tabs-3&quot;&gt;Tab 3&lt;/A&gt;&lt;/LI&gt;
	&lt;/UL&gt;

	&lt;div id=&quot;tabs-1&quot;&gt;	
		&lt;div id=&quot;accordion-1&quot;&gt;	
			&lt;H3&gt;&lt;A href=&quot;#accordion-0&quot;&gt;Tab 1 Accordion 1&lt;/A&gt;&lt;/H3&gt;
			&lt;div&gt;&lt;table width=&quot;100%&quot; id=&quot;accTable-0&quot;&gt;&lt;/table&gt;&amp;nbsp;&lt;/div&gt;
			&lt;H3&gt;&lt;A href=&quot;#accordion-1&quot;&gt;Tab 1 Accordion 2&lt;/A&gt;&lt;/H3&gt;
			&lt;div&gt;&lt;table width=&quot;100%&quot; id=&quot;accTable-1&quot;&gt;&lt;/table&gt;&amp;nbsp;&lt;/div&gt;
			&lt;H3&gt;&lt;A href=&quot;#accordion-2&quot;&gt;Tab 1 Accordion 3&lt;/A&gt;&lt;/H3&gt;
			&lt;div&gt;&lt;table width=&quot;100%&quot; id=&quot;accTable-2&quot;&gt;&lt;/table&gt;&amp;nbsp;&lt;/div&gt;	
		&lt;/div&gt;	
	&lt;/div&gt;
	&lt;div id=&quot;tabs-2&quot;&gt;
	&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; id=&quot;tabs-2-table&quot;&gt;&lt;/table&gt;
		&lt;div id=&quot;accordion-2&quot;&gt;	
			&lt;H3&gt;&lt;A href=&quot;#accordion-3&quot;&gt;Tab 2 Accordion 1&lt;/A&gt;&lt;/H3&gt;
			&lt;div&gt;&lt;table width=&quot;100%&quot; id=&quot;accTable-3&quot;&gt;&lt;/table&gt;&amp;nbsp;&lt;/div&gt;
			&lt;H3&gt;&lt;A href=&quot;#accordion-4&quot;&gt;Tab 2 Accordion 2&lt;/A&gt;&lt;/H3&gt;
			&lt;div&gt;&lt;table width=&quot;100%&quot; id=&quot;accTable-4&quot;&gt;&lt;/table&gt;&amp;nbsp;&lt;/div&gt;
			&lt;H3&gt;&lt;A href=&quot;#accordion-5&quot;&gt;Tab 2 Accordion 3&lt;/A&gt;&lt;/H3&gt;
			&lt;div&gt;&lt;table width=&quot;100%&quot; id=&quot;accTable-5&quot;&gt;&lt;/table&gt;&amp;nbsp;&lt;/div&gt;	
		&lt;/div&gt;
	&lt;/div&gt;
	&lt;div id=&quot;tabs-3&quot;&gt;
		&lt;div id=&quot;accordion-3&quot;&gt;	
			&lt;H3&gt;&lt;A href=&quot;#accordion-6&quot;&gt;Tab 3 Accordion 1&lt;/A&gt;&lt;/H3&gt;
			&lt;div&gt;&lt;table width=&quot;100%&quot; id=&quot;accTable-6&quot;&gt;&lt;/table&gt;&amp;nbsp;&lt;/div&gt;
			&lt;H3&gt;&lt;A href=&quot;#accordion-7&quot;&gt;Tab 3 Accordion 2&lt;/A&gt;&lt;/H3&gt;
			&lt;div&gt;&lt;table width=&quot;100%&quot; id=&quot;accTable-7&quot;&gt;&lt;/table&gt;&amp;nbsp;&lt;/div&gt;
			&lt;H3&gt;&lt;A href=&quot;#accordion-8&quot;&gt;Tab 3 Accordion 3&lt;/A&gt;&lt;/H3&gt;
			&lt;div&gt;&lt;table width=&quot;100%&quot; id=&quot;accTable-8&quot;&gt;&lt;/table&gt;&amp;nbsp;&lt;/div&gt;	
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/DIV&gt;

&lt;link type=&quot;text/css&quot; href=&quot;/test/English/Javascript/jQueryUI/jquery-ui-1.7.2.custom.css&quot; rel=&quot;stylesheet&quot; /&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/jquery-1.3.2.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/jQueryUI/jquery-ui-1.7.2.custom.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
// Array of all fields - format: accordionID|FieldInternalName
arrTabAccordion = ['0|Title','0|Dummyfield1','0|Dummyfield2',
			'1|Dummyfield3','1|Dummyfield4','1|Dummyfield5',
			'2|Dummyfield6','2|Dummyfield7','2|Dummyfield8',
			'3|Dummyfield9','3|Dummyfield10','3|Dummyfield11',
			'4|Dummyfield12','4|Dummyfield13','4|Dummyfield14',
			'5|Dummyfield15','5|Dummyfield16','5|Dummyfield17',
			'6|Dummyfield18','6|Dummyfield19','6|Dummyfield20',
			'7|Dummyfield21','7|Dummyfield22','7|Dummyfield23',
			'8|Dummyfield24','8|Dummyfield25','8|Dummyfield26'];

arrTab = ['1|FieldInTab1','1|FieldInTab2'];

// Initiate all the fields
fields = init_fields();

// Add the &quot;tabs&quot; to the formtable
$(&quot;#tabs&quot;).insertAfter('.ms-formtable').tabs();
// Add accordion
$(&quot;#accordion-1&quot;).accordion({autoHeight: false,animated: false,collapsible: true,active: false});
$(&quot;#accordion-2&quot;).accordion({autoHeight: false,animated: false,collapsible: true,active: false});
$(&quot;#accordion-3&quot;).accordion({autoHeight: false,animated: false,collapsible: true,active: false});

// Loop trough all fields and move them to the right accordion section
$.each(arrTabAccordion,function(idx,item){
	var split = item.split('|');
	var accID = split[0];
	var fieldName = split[1];
	if(fields[fieldName]!=undefined){
		currField = $(fields[fieldName]);
		currField.appendTo('#accTable-'+accID);
	}
});

// Loop trough all fields and move them to the right tab
$.each(arrTab,function(idx,item){
	var split = item.split('|');
	var tabID = split[0];
	var fieldName = split[1];
	if(fields[fieldName]!=undefined){
		currField = $(fields[fieldName]);
		currField.appendTo('#tabs-2-table');		
	}
});

// Fix IE8 issue with zoom
$(&quot;.ui-accordion-content&quot;).css({'zoom':1,'padding':'0px'});

// function - to make &quot;object&quot; of all tr's in the form
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;

This example is setup in a custom list with 26 single line text fields (Dummyfield1-26).

I have stripped off everything related to selecting the correct tab or accordion on form validation.

I may update this code later.

Regards
Alexander

Validate text field input against value in another list

I got this request from Sonaly:

I am using MOSS.

I have two lists Machines and TRansactions.

I have 3 following textboxes in newform.aspx/editform.aspx of Transactions List.

EnqNo – Plain Text box – Required field
Date – Datetime field – Required field
MachineID – Plain Text box – Required field

Here I want to validate Machine ID from Machines List (MachineId column) before save record into transaction list

Let me know if you need more information,


Alexander Says:
Take a look at this script: Convert Singleline textfield to filtered lookup dropdown and see if this could fill your need.

The script will convert your “MachineID” to a lookup from the list “Machines”.

Alexander


Sonaly Says:
Alexandar

I dont want to use lookup field as I have 1000+ item and it is not user friendly , that is why I am thinking of using Textbox coumn and validation.

Any other advise


This example has a two list setup with only the “Title” field present in each list. You will have to edit the FieldInternalName to match your fields.

Add this code to a CEWP below the form in NewForm and EditForm in the list the user will input the value in:

&lt;style type=&quot;text/css&quot;&gt;
.customError{
	background-color:#FF6A6A;
}
&lt;/style&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/jquery-1.3.2.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/interaction.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/stringBuffer.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
fields = init_fields();

// Attach a function to the blur event of the &quot;Title&quot; field
$(fields['Title']).find('input').blur(function(){
	var thisVal = $(this).val();
	validateTextAgainstList($(this));
});

function validateTextAgainstList(obj){
str = obj.val();
wsBaseUrl = L_Menu_BaseUrl + '/_vti_bin/';
// Edit the &quot;Title&quot; to match your FieldInternalName
var query = &quot;&lt;Where&gt;&lt;Eq&gt;&lt;FieldRef Name='Title' /&gt;&lt;Value Type='Text'&gt;&quot;+str+&quot;&lt;/Value&gt;&lt;/Eq&gt;&lt;/Where&gt;&quot;;
// Edit the list GUID to match your list - or use the list's displayName
	var itemCount = queryItemCount('D54206E8-5E98-4DCD-9D3D-39C321FD0792',query);
	if(itemCount==0){		
		$(&quot;input[id$='SaveItem']&quot;).attr('disabled',true);
		obj.addClass('customError');
		alert(&quot;Sorry mate, this value is not correct.&quot;);
	}else{
		// OK
		$(&quot;input[id$='SaveItem']&quot;).attr('disabled',false);
		obj.removeClass('customError');
	}
}

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 will have to edit the FieldRef Name=’Title’ to match your fields FieldInternalName, and the list GUID (D54206E8-5E98-4DCD-9D3D-39C321FD079) to match your list – or use the list’s displayName.

The jQuery-library is found here. 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.

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.

Regards
Alexander

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:

=&quot;&quot;

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:

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

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:

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

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 &quot;_spUserId&quot; 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 &quot;Rating&quot; column
		$(&quot;.ms-viewheadertr th&quot;).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
		$(&quot;.ms-viewheadertr th&quot;).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(&quot;Both the column with FieldInternalName &quot;&quot;+FieldInternalName+&quot;&quot; and the ID-column must be in the view.&quot;);
			return false;
		}
	}

	$(&quot;table.ms-listviewtable tbody:not([id^='aggr']) &gt;tr[beenthere!=1]:has(td.ms-vb2)&quot;).each(function(){
		$(this).attr('beenthere',1);
		var itemAlreadyRate = false;
		var thisTd = $(this).find(&quot;td[cellIndex=&quot; + colIndex + &quot;]&quot;);
		var thisIdColumn = $(this).find(&quot;td[cellIndex=&quot; + IdColIndex + &quot;]&quot;);
		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 &amp;&amp; currentRatingObj[thisId]['ratedByMe']==true){
				itemAlreadyRate = true;
			}
			rPos = currentRatingObj[thisId]['Plus'];
			rNeg = currentRatingObj[thisId]['Minus'];
		}
		// Rated in this session
		if(sessvars[thisListsGuid+thisId]==1 &amp;&amp; currentRatingObj!=false){
			itemAlreadyRate = true;
		}

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

function getRating(){
// Path to webservices
wsBaseUrl = L_Menu_BaseUrl + '/_vti_bin/';
var query = &quot;&lt;Where&gt;&lt;Eq&gt;&lt;FieldRef Name='ListGuid' /&gt;&lt;Value Type='Text'&gt;&quot;+ctx.listName+&quot;&lt;/Value&gt;&lt;/Eq&gt;&lt;/Where&gt;&quot;;
var rating = queryItems('RatingForSharePoint',query,['Plus','Minus','ItemID','Author']);
	if(rating.count==-1){
		alert(&quot;An error occured in the query:n&quot;+query);
	}else if(rating.count&gt;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']&gt;0){
					ratingObj[item['ItemID']]['ratedByMeVal']=&quot;+1&quot;;
				}else{
					ratingObj[item['ItemID']]['ratedByMeVal']=&quot;-1&quot;;
				}
			}
		});
		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 &amp;&amp; currentRatingObj[thisId]['ratedByMe']==true){
			itemAlreadyRate = true;
		}
		rPos = currentRatingObj[thisId]['Plus'];
		rNeg = currentRatingObj[thisId]['Minus'];
	}
	// Rated in this session
	if(sessvars[thisListsGuid+thisId]==1 &amp;&amp; currentRatingObj!=false){
		itemAlreadyRate = true;
	}
	var thisTd = $(fields[FieldInternalName]).find('.ms-formbody');
	var str = &quot;&lt;div style='color:gray'&gt;&quot;;
	str += &quot;&lt;img &quot;;
	if(!itemAlreadyRate){
		str += &quot;onclick='javascript:rateMe(&quot;up&quot;,&quot;+thisId+&quot;)' title='Rate Up' &quot;;
		str += &quot;style='vertical-align:middle;cursor:pointer' &quot;;
	}else{
		str += &quot;title='You have already rated this item &quot;+currentRatingObj[thisId]['ratedByMeVal']+&quot;' &quot;;
		str += &quot;style='vertical-align:middle;cursor:no-drop' &quot;;
	}
	str += &quot;src='/_layouts/images/arrupi.gif'&gt;&quot;;
	str += &quot;&lt;span style='font-weight:bold;' id='rateUp_&quot;+thisId+&quot;'&gt;&quot;+rPos+&quot;&lt;/span&gt;&quot;;
	str += &quot;&lt;img &quot;;
	if(!itemAlreadyRate){
		str += &quot;onclick='javascript:rateMe(&quot;down&quot;,&quot;+thisId+&quot;)' title='Rate Down' &quot;;
		str += &quot;style='vertical-align:middle;cursor:pointer' &quot;;
	}else{
		str += &quot;title='You have already rated this item &quot;+currentRatingObj[thisId]['ratedByMeVal']+&quot;' &quot;;
		str += &quot;style='vertical-align:middle;cursor:no-drop' &quot;;
	}
	str += &quot;src='/_layouts/images/arrdowni.gif'&gt;&quot;;
	str += &quot;&lt;span style='font-weight:bold;' id='rateDown_&quot;+thisId+&quot;'&gt;&quot;+rNeg+&quot;&lt;/span&gt;&quot;;
	str += &quot;&lt;/div&gt;&quot;;
	// Write HTML
	thisTd.html(str);
}

function getRatingDispForm(itemID){
// Path to webservices
wsBaseUrl = L_Menu_BaseUrl + '/_vti_bin/';
var query = &quot;&lt;Where&gt;&lt;And&gt;&lt;Eq&gt;&lt;FieldRef Name='ListGuid' /&gt;&lt;Value Type='Text'&gt;&quot;+thisListsGuid+&quot;&lt;/Value&gt;&lt;/Eq&gt;&quot;+
			&quot;&lt;Eq&gt;&lt;FieldRef Name='ItemID' /&gt;&lt;Value Type='Text'&gt;&quot;+itemID+&quot;&lt;/Value&gt;&lt;/Eq&gt;&lt;/And&gt;&lt;/Where&gt;&quot;;
var rating = queryItems('RatingForSharePoint',query,['Plus','Minus','ItemID','Author']);
	if(rating.count==-1){
		alert(&quot;An error occured in the query:n&quot;+query);
	}else if(rating.count&gt;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']&gt;0){
					ratingObj[item['ItemID']]['ratedByMeVal']=&quot;+1&quot;;
				}else{
					ratingObj[item['ItemID']]['ratedByMeVal']=&quot;-1&quot;;
				}
			}
		});
		return ratingObj;
	}else{
		return false;
	}
}

/************************************************************
*********************** Shared Code ***********************
************************************************************/
function rateMe(upORdown,id){
if(typeof(ctx)=='object'){
	var listGuid=ctx.listName;
	var listTitle = $.trim($(&quot;td.ms-pagetitle&quot;).text());
}else{
	var listGuid=thisListsGuid;
	var listTitle = $.trim($(&quot;td.ms-pagetitle a&quot;).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($(&quot;#rateUp_&quot;+id).text());
			$(&quot;#rateUp_&quot;+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($(&quot;#rateDown_&quot;+id).text());
		$(&quot;#rateDown_&quot;+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':&quot;Rating for: &quot; + listTitle,
							'Plus':plus,
							'Minus':minus,
							'ListUrl':urlDir,
							'ListGuid':listGuid,
							'ListName':listTitle,
							'ItemID':id});
	}
}

// Attaches a call to the function to the &quot;expand grouped elements function&quot; for it to function in grouped listview's
function ExpGroupRenderData(htmlToRender, groupName, isLoaded){
	var tbody=document.getElementById(&quot;tbod&quot;+groupName+&quot;_&quot;);
	var wrapDiv=document.createElement(&quot;DIV&quot;);
	wrapDiv.innerHTML=&quot;&lt;TABLE&gt;&lt;TBODY id=&quot;tbod&quot;+groupName+&quot;_&quot; isLoaded=&quot;&quot;+isLoaded+&quot;&quot;&gt;&quot;+htmlToRender+&quot;&lt;/TBODY&gt;&lt;/TABLE&gt;&quot;;
	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&gt;0){
		var qpart = urlSearch.substring(1).split('&amp;');
		$.each(qpart,function(i,item){
			var splitAgain = item.split('=');
			qObj[splitAgain[0]] = splitAgain[1];
		});
	}
return qObj;
}

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;
}

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