All posts by Alexander Bautz

Tabs in SharePoint form

18.01.2011 I have posted a new solution compatible with both SP2007 and SP2010 and fixes the problems with rich text fields and “single lookup with more than 20 items under Internet Explorer – problem”. You find it her


23.01.2010 Updated the code to fix two issues regarding date and time columns. I added a <style> tag to set the font size of “.ms-dtinput” and “.ms-dttimeinput” to 0.7em.

I also added a custom handler to select the right tab on “empty field validation” on a date and time field. These are validated without page reload, and therefore did not work in the previous version.

Thank you all for the feedback and the testing.

15.12.2009 Update to support form validation. On submit – if there are required fields not filled – the tab containing the first required field is selected.


I got this request:

We have a custom list with a lot of fields. I need to divide it into sections and then easily show/hide those sections. I am going to try dividing the form into div tags and then use jQuery to display the sections in either Tabs or an accordion…

And made this demo based on the jQuery UI Widget “Tabs”.

NewForm:
IMG
DispForm:
IMG
DispForm with attachment:
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

A folder named “jQueryUI” containing the scripts and the “images”-folder for the selected theme:
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 jQuery UI-library is found here. Find the theme of your choice – mine is “smootness” – and download the files (i have plucked only the necessary files – “UI Core” and “Tabs”).

Add a CEWP below your NewForm, DispForm and EditForm.

Add this 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;LI&gt;&lt;A href=&quot;#tabs-4&quot;&gt;Attachments&lt;/A&gt;&lt;/LI&gt;
	&lt;/UL&gt;

	&lt;div&gt;&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; id=&quot;tabs-1&quot;&gt;&lt;/table&gt;&lt;/div&gt;
	&lt;div&gt;&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; id=&quot;tabs-2&quot;&gt;&lt;/table&gt;&lt;/div&gt;
	&lt;div&gt;&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; id=&quot;tabs-3&quot;&gt;&lt;/table&gt;&lt;/div&gt;
	&lt;div&gt;&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; id=&quot;tabs-4&quot;&gt;&lt;/table&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: tabID|FieldInternalName
arrTab = ['1|Title','1|Tab1Text','1|Tab1Choice',
		  '2|Responsible','2|Tab2Text','2|Tab2Choice','2|Date',
		  '3|Tab3Text','3|Tab3Choice','3|Tab3MultilinePlain'];

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

// Add the &quot;tabs&quot; to the formtable
$(&quot;#tabs&quot;).insertAfter('.ms-formtable').tabs();
// 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-'+tabID);		
	}
});

// Are there any required fields not filled? - select the tab containing the first field
selectTabOnFormValidation(false);
function selectTabOnFormValidation(preSave){
var formvalidationTab = '';
// Formvalidation - find the first tab with empty required fields
	$.each(arrTab,function(idx,item){
		var split = item.split('|');
		var tabID = split[0];
		var fieldName = split[1];
		currField = $(fields[fieldName]);
		// Handles DateTimeField (empty field validation is performed without page reload)
		if(currField.find(&quot;SPAN[ID*='_DateTimeField_']&quot;).length&gt;0){
			if(currField.find('input:first').val()=='' &amp;&amp; preSave){
				formvalidationTab = tabID;
			}
		}
		if(formvalidationTab == '' &amp;&amp; currField.find('.ms-formbody span.ms-formvalidation').length&gt;0){
			formvalidationTab = tabID;
		}
	});
	// Select the first tab containing an empty required field
	if(formvalidationTab!=''){
		$('#tabs').tabs('select', formvalidationTab);
	}
}

// Move the Attachment's to the last tab
$(&quot;#idAttachmentsRow&quot;).appendTo('#tabs-4').find('.ms-formlabel').attr('width','165px');

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

// Catch &quot;empty field validation&quot; on date and time columns
function PreSaveAction(){
selectTabOnFormValidation(true);
return true;
}
&lt;/script&gt;

The only parameters you need to edit in the script is the array of FieldInternalNames. The format of the variable “arrTab” is tabID|FieldInternalName.

In the html above the script, adapt the number’s of tabs – and the tab’s display name. The tabID corresponds with the number in the id attribute of the table to insert the tab content in.

All fields must be added to a tab – if not it looks ugly….

Note: By now i have tested and found that columns of type “Multiple lines of text (Rich text or Enhanced rich text) do not work. What happens is that the tabs script shows some of the fields hidden parts.

I have not done any testing on how to prevent this issue, so feel free to notify me if you find a workaround.

Regards
Alexander

Edit date, single line text, number or boolean columns directly in list view

31.03.2010 updated the code and reworked the article:

This solution enables you to edit a column of type “Date and Time (Date Only)”, “Single line of text”, “Number”, “Currency”, “Yes/No” and “single choice people picker” directly in a list view.

I’m planning on updating with support for columns columns later on.

Double click on a “TD” to edit – this action is per “TD”.
IMG

In this picture all “TD’s” are double clicked on.
IMG

The people picker is created with the jQuery UI widget “Autocomplete”.
IMG

When saved OK – a picture is appended to indicate “Save OK”.
IMG

A different picture is appended on save error.
IMG

This can be used in lists and document library’s, but requires that a the ID column is in the view (it can be hidden in the script by setting the argument “hideIdColumn” to true).

I have added support for “date”, “single line text”, “number”, “currency”, “boolean” and “single choice people picker” columns. I will update this article with support for choice columns later on.

All these columns – for filtering purposes – supply their FieldInternalName in the list header. This way i do not have to specify the column index where it is found – it dynamically adapts to changing column order.

This solution can be used with plain list view’s and grouped view’s.

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.

Read here how to find the list Guid of your list, and how to find the FieldInternalName of your columns.

I have made one modification in the file “jquery-ui-1.8.custom.css” to correct the datepicker positioning of the date and year dropdowns. The style “.ui-datepicker select.ui-datepicker-year { width: 49%;}” is modified like this: “.ui-datepicker select.ui-datepicker-year { width: auto;}”. This might not affect your setup, and is merely a detail.

The sourcecode for “EditInListView.js” is provided below.

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

&lt;style type=&quot;text/css&quot;&gt;
.ui-menu .ui-menu-item {
	font-size:xx-small;
}
&lt;/style&gt;
&lt;link type=&quot;text/css&quot; href=&quot;/test/English/jQueryUI18/smoothness/jquery-ui-1.8.custom.css&quot; rel=&quot;stylesheet&quot; /&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/jquery-1.4.min.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/jQueryUI18/jquery-ui-1.8.custom.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/EditInListView.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
// Set variables
	hoverImgSrc = '/_layouts/images/DOWNARRW.GIF';
	hoverImgMouseOver = 'Double click to edit';
	successImgSrc = '/_layouts/images/ServiceInstalled.gif';
	failureImgSrc = '/_layouts/images/ServiceNotInstalled.gif';
	dateFormat = 'm/d/yy'; // alternative d.m.yy
	decimalSeparator = '.'; // The symbol used to mark the boundary between the integral and the fractional parts of a decimal number
	boolYesNoText = 'Yes|No'; // The display text in list view for a Yes/No-field
	userListGuid = '570D772F-0EAB-45A8-8C54-9CCD4EC6A0AF';
	userListBaseUrl = ''
	arrToEdit = ['MyDateField','SingleLine','Number','YesNo','MyPeoplePicker'];
	
// Call function
	initCustomEditFunction(true);
&lt;/script&gt;

Edit the array “arrToEdit” to hold your FieldInternalNames, the “userListGuid” to hold your list guid, and other parameters if necessary.

Parameter’s explained:

  • hoverImgSrc: The source of the image indicating editable field
  • hoverImgMouseOver: The mouse over on the “hoverImgSrc-image”
  • successImgSrc: The source of the image displayed when saving the new value succeeds
  • failureImgSrc: The source of the image displayed when saving the new value fails
  • dateFormat: ‘m/d/yy’ – alternative ‘d.m.yy’
  • decimalSeparator: The symbol used to mark the boundary between the integral and the fractional parts of a decimal number
  • boolYesNoText: The display text in list view for a Yes/No-field – format: Yes|No
  • userListGuid: The list guid for the userlist, used for the people picker
  • userListBaseUrl: Base URL for the list “People and Groups”. If in a managed path, reflect this path, else set to “” (blank string)
  • arrToEdit: Array of FieldInternalNames to address

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

/* Edit date, single line text, number, currency, boolean or single choice people picker directly in list view
 * ---------------------------------------------
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * https://spjsblog.com
 * v1.1
 * LastMod: 31.03.2010
 * ---------------------------------------------
 * Must include reference to:
 *  jquery-1.4 - http://jquery.com
 *  jquery-ui-1.8 - http://jqueryui.com/
 *  interaction.js - http://spjslib.codeplex.com
 *  stringBuffer.js - http://spjslib.codeplex.com
 * ---------------------------------------------
 *
 * Call from CEWP BELOW the list view like this:  
	&lt;style type=&quot;text/css&quot;&gt;
	.ui-menu .ui-menu-item {
		font-size:xx-small;
	}
	&lt;/style&gt;
	&lt;link type=&quot;text/css&quot; href=&quot;/test/English/jQueryUI18/smoothness/jquery-ui-1.8.custom.css&quot; rel=&quot;stylesheet&quot; /&gt;
	&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/jquery-1.4.min.js&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/jQueryUI18/jquery-ui-1.8.custom.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/EditInListView.js&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot;&gt;
	// Set variables
		hoverImgSrc = '/_layouts/images/DOWNARRW.GIF';
		hoverImgMouseOver = 'Double click to edit';
		successImgSrc = '/_layouts/images/ServiceInstalled.gif';
		failureImgSrc = '/_layouts/images/ServiceNotInstalled.gif';
		dateFormat = 'm/d/yy'; // alternative d.m.yy
		decimalSeparator = '.'; // The symbol used to mark the boundary between the integral and the fractional parts of a decimal number
		boolYesNoText = 'Yes|No'; // The display text in list view for a Yes/No-field
		userListGuid = '570D772F-0EAB-45A8-8C54-9CCD4EC6A0AF';
		userListBaseUrl = ''
		arrToEdit = ['MyDateField','SingleLine','Number','YesNo','MyPeoplePicker'];
		
	// Call function
		initCustomEditFunction(true);
	&lt;/script&gt;
*/

function initCustomEditFunction(hideIdColumn){
	if(typeof(hideIdColumn)!='undefined'){
		hideId = hideIdColumn;
		$(&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).addClass('dummyHideClass');
				}
			}
		});	
	}
	
	if(typeof(IDcolIndex)=='undefined'){
		alert(&quot;The ID column must be in the view.nYou may hide it in the script call by setting the argument &quot;hideIdColumn&quot; to true.&quot;);
	}

	if(typeof(arrTH)=='undefined'){
		arrTH = [];
		$(&quot;.ms-viewheadertr th&quot;).each(function(){
		var colIndex = $(this).attr('cellIndex');
			var table = $(this).find('table');
			if(table.attr('name')!=undefined){	
				var fldIntName = table.attr('name');
				var fldType = table.attr('fieldtype');			
				if($.inArray(fldIntName,arrToEdit)&gt;-1){
					arrTH.push({'colIndex':colIndex,'fldType':fldType,'fldIntName':fldIntName});
				}
			}
		});	
	}

	addCustomEditFunction(arrTH);
	// Hide ID column if specified
	if(hideId){
		$(&quot;.dummyHideClass&quot;).hide();
	}
}

function addCustomEditFunction(arrToInclude){
	$(&quot;table.ms-listviewtable tbody&quot;).each(function(){
		if($(this).attr('id').match('aggr')==null){
			$(this).find(&quot;tr:has(td.ms-vb2)[beenthere!='1']&quot;).each(function(){
				$(this).attr('beenthere','1');	
				var itemID = $(this).find(&quot;&gt;td[cellIndex=&quot; + IDcolIndex + &quot;]&quot;).text();
				// Hide ID column
				if(hideId){
					$(this).find(&quot;td[cellIndex=&quot;+IDcolIndex+&quot;]&quot;).addClass('dummyHideClass');
				}
				var pTR = $(this);	
				$.each(arrToInclude,function(idx,obj){		
					var col = obj['colIndex'];
					var type = obj['fldType'];
					var intName = obj['fldIntName'];		
					var TD = pTR.find(&quot;&gt;td[cellIndex=&quot; + col + &quot;]&quot;);
					var currVal = TD.text();
					// Add onclick and append image
					TD.dblclick(function(){editCurrentLine(type,itemID,intName)})
						.attr({'id':'customEdit_'+intName+&quot;_&quot;+itemID,'fieldType':type})
						.css({'cursor':'pointer'});
					if(type=='Number' || type=='Currency'){
						TD.find('div').append(&quot;&amp;nbsp;&lt;img style='vertical-align:middle' title='&quot; + hoverImgMouseOver + &quot;' src='&quot; + hoverImgSrc + &quot;'&gt;&quot;);
					}else if(type=='User'){
						if(TD.find('tr').length&gt;0){
							TD.find('tr:first').append(&quot;&lt;td&gt;&amp;nbsp;&lt;img style='vertical-align:middle' title='&quot; + hoverImgMouseOver + &quot;' src='&quot; + hoverImgSrc + &quot;'&gt;&lt;/td&gt;&quot;);
						}else{
							TD.append(&quot;&lt;div style='padding-left:12px'&gt;&amp;nbsp;&lt;img style='vertical-align:middle' title='&quot; + hoverImgMouseOver + &quot;' src='&quot; + hoverImgSrc + &quot;'&gt;&lt;/div&gt;&quot;);
						}
					}else{
						TD.append(&quot;&amp;nbsp;&lt;img style='vertical-align:middle' title='&quot; + hoverImgMouseOver + &quot;' src='&quot; + hoverImgSrc + &quot;'&gt;&quot;);
					}		
				});
			});
		}else if($(this).attr('id').match('aggr')!=null &amp;&amp; $(this).attr('beenthere')!='1' &amp;&amp; hideId){
			$(this).attr('beenthere','1');
			$(this).find(&quot;td[cellIndex=&quot;+IDcolIndex+&quot;]&quot;).addClass('dummyHideClass');
		}	
	});
}

function editCurrentLine(type,id,intName){
var currField = $(&quot;#customEdit_&quot; + intName+&quot;_&quot;+id);
var currVal = currField.text();
// Remove &amp;nbsp;
currVal = $.trim(currVal.replace(/xA0/g,''));
	if(type=='DateTime'){
		if(currVal.indexOf(' ')&gt;-1){
			currVal = currVal.substring(0,currVal.indexOf(' ')); // Strip off any &quot;time-value&quot;
		}	
		if($(&quot;#customEditInput_&quot;+intName+&quot;_&quot;+id).length==0){
			currField.css({'width':currField.width()}).html(&quot;&lt;div&gt;&amp;nbsp;&lt;a title='Cancel' href='javascript:' onclick='javascript:cancelCustomSaveLine(&quot;&quot;+intName+&quot;&quot;,&quot;&quot;+id+&quot;&quot;,&quot;&quot;+currVal+&quot;&quot;)'&gt;cancel&lt;/a&gt;&amp;nbsp;|&amp;nbsp;&quot; +
			&quot;&lt;a title='Clear' href='javascript:' onclick='javascript:customSaveLine(&quot;&quot;+intName+&quot;&quot;,&quot;&quot;+id+&quot;&quot;,&quot;&quot;+currVal+&quot;&quot;,&quot; + true + &quot;)'&gt;clear&lt;/a&gt;&lt;br&gt;&quot; +
			&quot;&lt;input class='ms-input' id='customEditInput_&quot;+intName+&quot;_&quot;+id+&quot;' style='width:1px;height:1px;border:0px' value='&quot; + currVal + &quot;' /&gt;&lt;/div&gt;&quot;);
			// Datepicker
			$(&quot;#customEditInput_&quot; + intName+&quot;_&quot;+id).datepicker({ 
				dateFormat: dateFormat,
		    	changeMonth: true,
		   		changeYear: true,
		   		showButtonPanel: true,
		   		onSelect: function(dateText, inst){		   			
		   			customSaveLine(intName,id,currVal);
		   		}		   			
		   	}).datepicker('show');
		}
	}else if(type=='Text' || type=='Number' || type=='Currency'){
		if($(&quot;#customEditInput_&quot;+intName+&quot;_&quot;+id).length==0){
			currField.css({'width':currField.width()}).html(&quot;&lt;div&gt;&amp;nbsp;&lt;a title='Save' href='javascript:' onclick='javascript:customSaveLine(&quot;&quot;+intName+&quot;&quot;,&quot;&quot;+id+&quot;&quot;,&quot;&quot;+currVal+&quot;&quot;)'&gt;save&lt;/a&gt;&amp;nbsp;|&amp;nbsp;&quot; +
				&quot;&lt;a title='Cancel' href='javascript:' onclick='javascript:cancelCustomSaveLine(&quot;&quot;+intName+&quot;&quot;,&quot;&quot;+id+&quot;&quot;,&quot;&quot;+currVal+&quot;&quot;)'&gt;cancel&lt;/a&gt;&lt;br&gt;&quot; +
				&quot;&lt;input class='ms-input' id='customEditInput_&quot;+intName+&quot;_&quot;+id+&quot;' style='width:99%' value='&quot; + currVal + &quot;' /&gt;&lt;/div&gt;&quot;);								
			// Focus on the input
			setTimeout(function(){currField.find('input').focus();},250);		
			// Add keyup/down function
			currField.find('input').keyup(function(e){
			// If number - restrict input to numbers only - may need a little more tweaking
				if(type=='Number' || type=='Currency'){
				var reg = new RegExp(&quot;[^0-9|\&quot; + decimalSeparator + &quot;]&quot;,'g');
					var thisVal = $(this).val().replace(reg,'');
					$(this).val(thisVal);					
				}
			}).keydown(function(e){
				// Enter = save
				if(e.keyCode==13){
					customSaveLine(intName,id,currVal)
				}
			}).keyup();							
		}
	}else if(type=='Boolean'){
		if($(&quot;#customEditInput_&quot;+intName+&quot;_&quot;+id).length==0){		
			if(currVal=='' || currVal.toLowerCase().indexOf('n')&gt;-1){ // 'n' is found in 'No' and in Norwegian 'Nei'
				chk='';
			}else{
				chk='checked';
			}			
			currField.css({'width':currField.width()}).html(&quot;&lt;div&gt;&amp;nbsp;&lt;a title='Cancel' href='javascript:' onclick='javascript:cancelCustomSaveLine(&quot;&quot;+intName+&quot;&quot;,&quot;&quot;+id+&quot;&quot;,&quot;&quot;+currVal+&quot;&quot;)'&gt;cancel&lt;/a&gt;&lt;br&gt;&quot; +
				&quot;&lt;input type='checkbox' id='customEditInput_&quot;+intName+&quot;_&quot;+id+&quot;' &quot; + chk + &quot;/&gt;&lt;/div&gt;&quot;);								
			$(&quot;#customEditInput_&quot;+intName+&quot;_&quot;+id).click(function(){
				customSaveLine(intName,id,currVal)
			}).focus();					
		}
	}else if(type=='User'){
		if($(&quot;#customEditInput_&quot;+intName+&quot;_&quot;+id).length==0){
			currField.css({'width':currField.width()}).html(&quot;&lt;div&gt;&amp;nbsp;&lt;a title='Cancel' href='javascript:' onclick='javascript:cancelCustomSaveLine(&quot;&quot;+intName+&quot;&quot;,&quot;&quot;+id+&quot;&quot;,&quot;&quot;+currVal+&quot;&quot;)'&gt;cancel&lt;/a&gt;&amp;nbsp;|&amp;nbsp;&quot; +
				&quot;&lt;a title='Clear' href='javascript:' onclick='javascript:customSaveLine(&quot;&quot;+intName+&quot;&quot;,&quot;&quot;+id+&quot;&quot;,&quot;&quot;+currVal+&quot;&quot;,&quot; + true + &quot;)'&gt;clear&lt;/a&gt;&lt;br&gt;&quot; +
				&quot;&lt;input title='Type into the textfield to get a list of users' class='ms-input' id='customEditInput_&quot;+intName+&quot;_&quot;+id+&quot;' style='width:99%' value='&quot; + currVal + &quot;' /&gt;&lt;/div&gt;&quot;);								
			// Autocomplete
			if(typeof(allUsers)=='undefined'){
				allUsers = getUsers();
			}
			currField.find('input').autocomplete({
				source: allUsers,
				select: function(event, ui){
					$(this).attr('hiddenVal',ui.item.userID);
					customSaveLine(intName,id,currVal);									
					return false;
				}		
			});
			// Focus on the input
			setTimeout(function(){currField.find('input').focus();},250);						
		}
	}
}

function getUsers(){
	var query = &quot;&lt;Where&gt;&lt;And&gt;&lt;IsNotNull&gt;&lt;FieldRef Name='EMail' /&gt;&lt;/IsNotNull&gt;&quot; +
				&quot;&lt;Eq&gt;&lt;FieldRef Name='ContentType' /&gt;&lt;Value Type='Text'&gt;Person&lt;/Value&gt;&lt;/Eq&gt;&lt;/And&gt;&lt;/Where&gt;&quot; +
				&quot;&lt;OrderBy&gt;&lt;FieldRef Name='Title' Ascending='TRUE'/&gt;&lt;/OrderBy&gt;&quot;;
	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']+&quot;&lt;br&gt;&quot;+item['EMail']+&quot;&lt;br&gt;&quot;+item['Name'],value:item['Title'],userID:item['ID']});	
    });
    return ret;    
}

function cancelCustomSaveLine(intName,id,currVal){
var pTD = $(&quot;#customEdit_&quot;+intName+&quot;_&quot;+id);
var type = pTD.attr('fieldType');
	if(type=='Number' || type=='Currency'){
		pTD.html(&quot;&lt;div align='right'&gt;&quot; + currVal + &quot;&amp;nbsp;&lt;img style='vertical-align:middle' src='&quot; + hoverImgSrc + &quot;'&gt;&lt;/div&gt;&quot;);
	}else if(type=='User'){
		pTD.html(&quot;&lt;div style='padding-left:12px'&gt;&quot; + currVal + &quot;&amp;nbsp;&lt;img style='vertical-align:middle' src='&quot; + hoverImgSrc + &quot;'&gt;&lt;/div&gt;&quot;);
	}else{
		pTD.html(currVal + &quot;&amp;nbsp;&lt;img style='vertical-align:middle' src='&quot; + hoverImgSrc + &quot;'&gt;&quot;);		
	}
}

function customSaveLine(intName,id,currVal,clear){
wsBaseUrl = ctx.HttpRoot + '/_vti_bin/';
listGuid = ctx.listName;

if(clear==undefined)clear=false;
var pTD = $(&quot;#customEdit_&quot;+intName+&quot;_&quot;+id);
	var type = pTD.attr('fieldType');
	var inpField = pTD.find('input');
	// Determine type and get value
	if(type=='Boolean'){
		var bSplit = boolYesNoText.split('|');
		var newVal = inpField.attr('checked');
		if(newVal){
			newVal='1';
			newValText=bSplit[0];
		}else{
			newVal='0';
			newValText=bSplit[1];
		}		
	}else{	
		var newVal = $.trim(inpField.val());
	}
	// Check if value has changed	
	if(newVal!=currVal || clear){
		var data = {};
		if(type=='DateTime'){
			if(clear){
				data[intName] = '';
				newVal = '';
			}else{
				var isoDate = parseISO8601Date(newVal);
				data[intName] = isoDate;
			}
		}else if(type=='User'){
			if(clear){
				data[intName] = &quot;&quot;;
				newVal = '';
			}else{
				data[intName] = inpField.attr('hiddenVal');
			}
		}else{
			data[intName] = newVal;
		}
		// Write back data
		var res = updateItem(listGuid,id,data);
		// Success or failure
		if(res.success){ // Save success
			if(type=='Number'){
				pTD.html(&quot;&lt;div align='right'&gt;&quot; + newVal + &quot;&amp;nbsp;&lt;img style='vertical-align:middle' title='Saved' src='&quot; + successImgSrc + &quot;' width='14' height='14' border='0'&gt;&lt;/div&gt;&quot;);
			}else if(type=='Boolean'){
				pTD.html(newValText + &quot;&amp;nbsp;&lt;img style='vertical-align:middle' title='Saved' src='&quot; + successImgSrc + &quot;' width='14' height='14' border='0'&gt;&quot;);
			}else if(type=='User'){
				pTD.html(&quot;&lt;div style='padding-left:12px'&gt;&quot; + newVal + &quot;&amp;nbsp;&lt;img style='vertical-align:middle' title='Saved' src='&quot; + successImgSrc + &quot;' width='14' height='14' border='0'&gt;&lt;/div&gt;&quot;);
			}else{
				pTD.html(newVal + &quot;&amp;nbsp;&lt;img style='vertical-align:middle' title='Saved' src='&quot; + successImgSrc + &quot;' width='14' height='14' border='0'&gt;&quot;);
			}
		}else{ // Failed to save
			if(type=='Number'){
				pTD.html(&quot;&lt;div align='right'&gt;&quot; + currVal + &quot;&amp;nbsp;&lt;img style='vertical-align:middle' style='vertical-align:middle' title='&quot; + res.errorText + &quot;' src='&quot; + failureImgSrc + &quot;' width='14' height='14' border='0'&gt;&lt;/div&gt;&quot;);
			}else if(type=='User'){
				pTD.html(&quot;&lt;div style='padding-left:12px'&gt;&quot; + currVal + &quot;&amp;nbsp;&lt;img style='vertical-align:middle' title='&quot; + res.errorText + &quot;' src='&quot; + failureImgSrc + &quot;' width='14' height='14' border='0'&gt;&lt;/div&gt;&quot;);
			}else{
				pTD.html(currVal + &quot;&amp;nbsp;&lt;img style='vertical-align:middle' title='&quot; + res.errorText + &quot;' src='&quot; + failureImgSrc + &quot;' width='14' height='14' border='0'&gt;&quot;);
			}
		}
	}else{ // If value is not changed, restore currVal
		if(type=='Number'){
			pTD.html(&quot;&lt;div align='right'&gt;&quot; + newVal + &quot;&amp;nbsp;&lt;img style='vertical-align:middle' title='&quot; + hoverImgMouseOver + &quot;' src='&quot; + hoverImgSrc + &quot;'&gt;&lt;/div&gt;&quot;);
		}else if(type=='User'){
			pTD.html(&quot;&lt;div style='padding-left:12px'&gt;&quot; + newVal + &quot;&amp;nbsp;&lt;img style='vertical-align:middle' title='&quot; + hoverImgMouseOver + &quot;' src='&quot; + hoverImgSrc + &quot;'&gt;&lt;/div&gt;&quot;);
		}else{
			pTD.html(newVal + &quot;&amp;nbsp;&lt;img style='vertical-align:middle' title='&quot; + hoverImgMouseOver + &quot;' src='&quot; + hoverImgSrc + &quot;'&gt;&quot;);
		}
	}
}

function parseISO8601Date(str){
	if(str!=''){
	var strSplit = str.split(dateFormat.charAt(1));
		switch(dateFormat){
			case 'm/d/yy':
				return strSplit[2] + &quot;-&quot; + strSplit[0] + &quot;-&quot; + strSplit[1] + &quot;T12:00:00Z&quot;; // set's clock to 12:00 PM
			break;
			case 'd.m.yy':
				return strSplit[0] + &quot;-&quot; + strSplit[2] + &quot;-&quot; + strSplit[1] + &quot;T12:00:00Z&quot;; // set's clock to 12:00 PM
			break;
		}
	}else{
		return '';
	}		
}

// 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);
initCustomEditFunction();
}

// Size of datepicker
$(&quot;body&quot;).css({'font-size':'55%'}); 

Save this code as “EditInListView.js”, and upload to your scriptlibrary as shown above.

Note: Due to the number of DOM-modifications there might be a performance issue (prolonged load time of the page) when used.

To minimize the issue you can try:

  • Limit the number of columns this feature is applied to
  • Limit the item count in each page
  • Group your items and set “By default, show groupings: Collapsed”

Test it in your environment to find what settings suites you.

Ask if something is unclear.

Regards
Alexander

Link to fill user login name in people picker

By request from Charlie:

Hi:
Similar to the “Date Picker Clicker”, do you know if I could click a link and the users login name would fill a People Picker (person or group)?… on a newform or editform?

Charlie Epes

Here is a solution for inserting current user’s login name in a people picker by clicking on a link above the field.

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 file “AccessUserProfileInWSS.js” is found here. Read the article as you have to set your “user list GUID” in the script.

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

Add a CEWP below – it is essential that it is placed below – your list-form as described here, 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/AccessUserProfileInWSS.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/SetPeoplePicker.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
// Array of fields to add this function to
  var arrOfFields = ['MyPeoplePicker','AnotherPeoplePicker'];
  initSetPeoplePicker(arrOfFields);
&lt;/script&gt;

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

/* Set people picker to current user login by click on a link above the field
 * ---------------------------------------------
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * https://spjsblog.com
 * v1.0
 * LastMod: 04.12.2009
 * ---------------------------------------------
 * Include reference to jquery - http://jquery.com
 *  interaction.js - http://spjslib.codeplex.com/
 *  stringBuffer.js - http://spjslib.codeplex.com/
 *  AccessUserProfileInWSS.js - https://spjsblog.com/2009/09/20/accessing-user-profile-information-in-wss-3-0-with-javascript/
 * ---------------------------------------------
 * Call from a CEWP below the list form in NewForm or EditForm like this:
	&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/AccessUserProfileInWSS.js&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot; src=&quot;/test/English/Javascript/SetPeoplePicker.js&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot;&gt;
	// Array of fields to add this function to
	  var arrOfFields = ['MyPeoplePicker','AnotherPeoplePicker'];
	  initSetPeoplePicker(arrOfFields);
	&lt;/script&gt;
*/

// Build the user information object
var ui = getUserInfo();

function initSetPeoplePicker(arr){
if(typeof(fields)=='undefined')fields = init_fields();
	$.each(arr,function(idx,item){
		// Check if FieldInternalName is correct
		if(fields[item]==undefined)return;
		// Add clickable link over field - ui.Title=DisplayName of current user
		$(fields[item]).find('.ms-formbody').prepend(&quot;&lt;div&gt;&lt;a title=&quot;Set field's value to &quot; + ui.Title + &quot;&quot; href=&quot;javascript:setPeoplePicker('&quot; + item + &quot;')&quot;&gt;[&quot; + ui.Title + &quot;]&lt;/a&gt;&lt;/div&gt;&quot;);	
	});
}

function setPeoplePicker(FieldInternalName){
var field = $(fields[FieldInternalName])
	if(field.find('.ms-inputuserfield:visible').length&gt;0){	
		// IE
		field.find('.ms-inputuserfield').html(ui.Name);
		field.find('img:first').click();	
	}else{
		// FF
		field.find(&quot;textarea:first&quot;).val(ui.Name);
	}
}

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 this code as “SetPeoplePicker.js”, and upload to the script library as shown above.

Ask if something is unclear.

Regards
Alexander

Set datefield to first day of month, today’s date or last day of month

Change log
April 9, 2014
Updated the code example to fix some quotes that was formatted wrong due to migrating from my old server a long time ago. I also updated the function init_fields in the example.

I got this request from Charlie:

Hi Alexander:
Is it possible to add a clickable “button” or icon next to a date picker that would insert “Today’s Date” into the field box?

Yes it is. Here’s a solution for setting either “first day of month”, “today” or “last day of month” by clicking on a link above the date picker, or by pressing “F”, “T” or “L” in the date picker field itself.

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 “DateFieldValueOnClick.js” is found below.

Add a CEWP belowit is essential that it is placed below – your list-form as briefly described here, and add this code:

<script type="text/javascript" src="/Javascript/jquery-1.11.2.min.js"></script>
<script type="text/javascript" src="/Javascript/DateFieldValueOnClick.js"></script>
<script type="text/javascript">
	// Array of fields to add this function to
	var arrOfFields = ['MyDateColumn1','MyDateColumn2'];
	setDateFieldValue(arrOfFields);
</script>

The variable “arrOfFields” is an array of the FieldInternalNames of all the date picker-fields you want to add this feature to.

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

/* Set datepicker value to "first day of month", "today" or "last day if month"
 * ---------------------------------------------
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * https://spjsblog.com
 * v1.1
 * LastMod: 09.04.2014 
*/

function setDateFieldValue(arrOfFieldInternalNames){
if(typeof fields === 'undefined')fields = init_fields_v2();
// Get today's date
var today = new Date();
var m = today.getMonth()+1;
var d = today.getDate();
var y = today.getFullYear();
// Find last day in month
var lastDayRaw = new Date(y,m,0);
var dLast = lastDayRaw.getDate();

// Format your date
var T = m + "/" + d + "/" + y; // Today
var F = m + "/" + 1 + "/" + y; // First day in month
var L = m + "/" + dLast + "/" + y; // Last day in month
var fieldMouseoverTitle = "Press \"F\" for " + F + ", \"T\" for " + T + ", \"L\" for " + L;
$.each(arrOfFields,function(idx,item){
if(fields[item]==undefined)return;
$(fields[item]).find('input').attr('title',fieldMouseoverTitle).keyup(function(e){
if(e.keyCode==70){
setDate(item,F);
}
if(e.keyCode==84){
setDate(item,T);
}
if(e.keyCode==76){
setDate(item,L);
}
}).parents('td.ms-formbody:first').prepend("<div><span title='Set field value to \"" + F + "\"' style='cursor:pointer;' onclick=setDate(\"" + item + "\",\"" + F +"\")>First</span> | <span title='Set field value to \"" + T + "\"' style='cursor:pointer;' onclick=setDate(\"" + item + "\",\"" + T + "\")>Today</span> | <span title='Set field value to \"" + L + "\"' style='cursor:pointer;' onclick='setDate(\"" + item + "\",\"" + L +"\")'>Last</span></div>");
});
}

function setDate(fieldName,date){
	$(fields[fieldName]).find('input').val(date);
}

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

Save this code as “DateFieldValueOnClick.js”, and upload to the script library as shown above.

Ask if something is unclear.

Regards
Alexander

Dynamic expand/collapse fields or array of fields by multi select

August 18, 2014 Brushed up the code example as it had some faulty quotes due to an error in the migration of the contents when I moved the blog some time ago.


25.03.2011 Fixed a bug in the DispForm code – thanks to Brian for noticing.


13.09.2010 Updated to support shared fields in the arrays – as requested by Larry.


This is a follow up on this article. You must read this article to get the basics before proceed with this one.

I will here give an example on how to use a multi select in stead of the single choice dropdown used in the previous article.

The only modification to the form from the previous , is the field “MySelect” which now should be changed to “Checkboxes (allow multiple selections)”.

The code for NewForm and EditForm should now be like this:

<!-- The jQuery version must be 1.6 or above -->
<script type="text/javascript" src="/Scripts/jquery-1.10.2.min.js"></script>
<script type="text/javascript">

var fields = init_fields_v2();
// Arrays of fields to show or hide
var arrRed = ['ShowIfRed1','ShowIfRed2'];
var arrBlue = ['ShowIfBlue1','ShowIfBlue2'];

// Multiselect
$(fields['MySelect']).find('input').each(function(i){
	// On page load
	if(i==0){ // call this only once
		multiSelectdynamicDisplay($(this));
	}
	// Add onclick
	$(this).click(function(){
		multiSelectdynamicDisplay($(this));
	});
});

function multiSelectdynamicDisplay(inp){
	var objChecked = {};
	var arrToHide = [];
	var arrToShow = [];
	var inpAll = inp.parents('td.ms-formbody:first').find('input');
	$.each(inpAll,function(){
		objChecked[$(this).next().text()] = $(this).prop('checked');
	});
	// Check each option
	if(objChecked['Red']){
		arrToShow = arrToShow.concat(arrRed);
	}else if(!objChecked['Red']){
		arrToHide = arrToHide.concat(arrRed);
	}
	
	if(objChecked['Blue']){
		arrToShow = arrToShow.concat(arrBlue);
	}else if(!objChecked['Blue']){
		arrToHide = arrToHide.concat(arrBlue);
	}	
	if(objChecked['Yellow']){
		//alert("No array defined for "Yellow"");
	}else if(!objChecked['Yellow']){
		// Has no array defined
	}
	// Hide
	toggleArr(arrToHide,true);
	// Show
	toggleArr(arrToShow,false);
}

function toggleArr(arr,hide){
	if(hide){
		for(i=0;i<arr.length;i++){
			$(fields[arr[i]]).hide();
		}
	}else if(!hide){
		for(i=0;i<arr.length;i++){
			$(fields[arr[i]]).show();
		}
	}
}

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>

The code for DispForm should now be like this:

<script type="text/javascript" src="/Scripts/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
var fields = init_fields_v2();
// Arrays of fields to show or hide
var arrRed = ['Title','ShowIfRed1','ShowIfRed2'];
var arrBlue = ['Title','ShowIfBlue1','ShowIfBlue2'];

// Hide all onload
var arrToHide = [];
arrToHide = arrToHide.concat(arrRed,arrBlue);
toggleArr(arrToHide,true);

// Find the ones selected
var c = $(fields['MySelect']).find('.ms-formbody').text().replace(/xA0/g,'');
cSplit = c.split('; ');
$.each(cSplit,function(idx,color){
	dynamicDisplay($.trim(color));
});

function dynamicDisplay(color){
var arrToShow = [];
	if(color=='Red'){
		arrToShow = arrToShow.concat(arrRed);
	}	
	if(color=='Blue'){
		arrToShow = arrToShow.concat(arrBlue);
	}	
	if(color=='Yellow'){
		// No array defined
	}
	// Show
	toggleArr(arrToShow,false);
}

function toggleArr(arr,hide){
  if(hide){
    for(i=0;i<arr.length;i++){
      $(fields[arr[i]]).hide();
    }
  }else if(!hide){
    for(i=0;i<arr.length;i++){
      $(fields[arr[i]]).show();
    }
  }
}

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>

This article is, as mentioned above, a follow up on anther article. Read the previous article to get the basics.

Ask if anything is unclear.

Regards
Alexander

Hide menu items in list view toolbar and views in view selector

This is a short one on how to remove menu items from the “New”, “Actions”, “Settings”, and “List view’s” menu in a list or document library.

This method requires a CEWP added below the list view web part with the code, and is a “per view code” which must be added to every view where the menu items shall be removed.

I will first give a list of the “names” of the “standard” elements found in the list view toolbar menu and list view menu, then i will give an example of how to remove selected items from the menu’s.

The menu items in the “Actions”, and the “Settings” menu has these “names” (the part of the ID used to locate them):

  • _EditInGridButton
  • _ExportToSpreadsheet
  • _ExportToDatabase
  • _ViewRSS
  • _SubscribeButton
  • _AddColumn
  • _AddView
  • _ListSettings

The “New” menu (the one containing all the “New-button” for all your content types) uses “_New0” for the first “_New1” for the next and so on.

The “view’s” menu uses these names for the “standard” menu items:

  • _DefaultView
  • _ModifyView
  • _CreateView

The custom made views uses the “DisplayName” of the view to identify it.

Code for hiding elements in “New”, “Actions”, “Settings” and “View’s” menu:

&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;
/* Hide menu items in list view toolbar and views in view selector
 * ---------------------------------------------
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * https://spjsblog.com
 * v1.0
 * LastMod: 26.11.2009
 * ---------------------------------------------
 * Include reference to:
 *  jquery - http://jquery.com
 * ---------------------------------------------
*/

// Remove menu items - in this example all items in the &quot;Settings&quot; menu are removed (and therefore the menu is removed)
// This is the array of menu items to hide
var arrOfMenuItemsToHide = ['_EditInGridButton','_AddView','_AddColumn','_ListSettings'];
$.each(arrOfMenuItemsToHide,function(idx,item){	
	$(&quot;*[id$='&quot; + item + &quot;']&quot;).next().andSelf().remove();
});

// Views - hides &quot;Modify&quot;, &quot;Create&quot; and the custom made &quot;My Test View&quot;
// This is the array of view's or to hide
var arrOfViewsToHide = ['_ModifyView','_CreateView','My Test View'];
$.each(arrOfViewsToHide,function(idx,item){	
	$.each($(&quot;*[id$='_ViewSelectorMenu']&quot;).children(),function(){
		if($(this).attr('id').match(item) || $(this).attr('text')==item){
			$(this).next().andSelf().remove();
		}
	});
});

// Remove the menu if all menu items are removed
$(&quot;.ms-menutoolbar&quot;).find('menu').each(function(){
	if($(this).children().length==0){
		$(this).parents('td.ms-toolbar:first').prev().andSelf().remove();
	}
});
&lt;/script&gt;

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.

This code can be adapted to hide elements based on group membership of the logged in user. I have written about a method to get the group collection for a user and to verify group membership here Showing or hiding list fields based on membership in a SharePoint group.

Ask if something is unclear.

Regards
Alexander

Count groups in grouped list view

This is a short one on counting groups in a grouped list view like this (group count in the list view toolbar):
IMG

Note: This counts only visible groups. If you set the “Number of groups to display per page” in the list view settings you will get max that number of groups when counting. An alternate approach would be to query the list for the total number of unique items based on the items the view is grouped by.

Add a CEWP below the list view with this code (alter the location of jQuery as needed):

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

// Grouping on level 1
var CountGrouping1 = $(&quot;.ms-listviewtable td.ms-gb&quot;).length;
var NameGrouping1 = $(&quot;.ms-listviewtable td.ms-gb:first a:eq(1)&quot;).text();

// Grouping on level 2
var CountGrouping2 = $(&quot;.ms-listviewtable td.ms-gb2&quot;).length;
var NameGrouping2 = $(&quot;.ms-listviewtable td.ms-gb2:first a:eq(1)&quot;).text();

var str = NameGrouping1 + &quot;'s: &quot; + CountGrouping1 + &quot; | &quot; + NameGrouping2 + &quot;'s: &quot; + CountGrouping2;

$(&quot;td.ms-toolbar[width='99%']&quot;).append(&quot;&lt;div class='ms-listheaderlabel' style='text-align:center;margin-top:-15px'&gt;&quot; + str + &quot;&lt;/div&gt;&quot;);

&lt;/script&gt;

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.

Ask if something is unclear.

Regards
Alexander

SharePoint list’s or document library’s: Primary key in selected field

05.01.2010 Small update to hide the “OK-button” if the “keyIsNotUniqueCount” is greater than 0.
25.11.2009 Small update to the script for placing the image correctly when used with the headings script.

In this article I will give you a solution for adding “primary key support” to a list or a document library with JavaScript.

This will work with fields of type “Single line of text”, “Multiple lines of text (Plain text)” and “Number”. Note that if you activate this feature for a field of type “Number”, it strips off all other than numbers 0-9. No spaces, commas or periods are allowed. This is done to avoid conflicts based on different formats used in different language settings.

You can enable this feature for more than one field in a list or document library.

Note: This does only work in NewForm and EditForm, not if edited in DataSheet.

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 “PrimaryKey.js” is found below.

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

The last file in this screen-shot is the Right click and select Save picture as. Right click on the image and select “Save picture as”.

Add a CEWP below your list-form in NewForm and EditForm.
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/PrimaryKey.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
   // Enables &quot;Primary key&quot; on the &quot;Title-field&quot;
   ensurePrimaryKey('Title','','/test/English/Javascript/PrimaryKey.gif','');
&lt;/script&gt;

Your “Title-field” will look like this:
IMG

The check is attached to the “blur” event, and triggers when you removes focus on the field. If you try to add a “non-unique-value” to that field, you end up with this warning, and cannot save the list item:
IMG

If used with a field of type “Number”, the code strips away spaces, commas and periods as described above.

Parameters explained:

  • FieldInternalName: FieldInternalName of the field to add this feature to
  • PrimaryKeyViolationWarning: [optional] The text shown under the field if the key is not unique.
  • keyImageSrc: [optional] Image source for the “key.image” added before the field label. If not supplied it default’s to “/_layouts/images/prf16.gif”.
  • PrimaryKeyHoverImageText: [optional] Description text if hovered over the “key-image”.

Sourcecode for the file “PrimaryKey.js”:

/* Primary key for lists or Document libraries
 * ---------------------------------------------
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * https://spjsblog.com
 * v1.1
 * LastMod: 05.01.2010
 * ---------------------------------------------
 * Include reference to:
 *  jquery - http://jquery.com
 *  interaction.js - http://spjslib.codeplex.com/
 *  stringBuffer.js - http://spjslib.codeplex.com/
 * ---------------------------------------------
 * Call from a CEWP below the list form in NewForm orEditForm like this:
	&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/PrimaryKey.js&quot;&gt;&lt;/script&gt;
	&lt;script type=&quot;text/javascript&quot;&gt;
		// Enables primary key for the &quot;Title-field&quot;
		ensurePrimaryKey('Title','This field's value has to be unique for this list.','/test/English/Javascript/PrimaryKey.gif','Primary key is enabled for this field');
	&lt;/script&gt;
*/

if(typeof(fields)=='undefined')fields = init_fields();
function ensurePrimaryKey(FieldInternalName,PrimaryKeyViolationWarning,keyImageSrc,PrimaryKeyHoverImageText){
	if(fields[FieldInternalName]!=undefined){
		listDisplayName = $(&quot;h2.ms-pagetitle a&quot;).text();
		keyIsNotUniqueCount = 0;
		// If PrimaryKeyViolationWarning is not defined, default to this text
		if(PrimaryKeyViolationWarning==undefined || PrimaryKeyViolationWarning==''){
			var PrimaryKeyViolationWarning = &quot;This field's value has to be unique for this list.&quot;;
		}
		// If PrimaryKeyHoverImageText is not defined, default to this text
		if(PrimaryKeyHoverImageText==undefined || PrimaryKeyHoverImageText==''){
			var PrimaryKeyHoverImageText = &quot;Primary key is enabled for this field&quot;;
		}
		if(keyImageSrc==undefined || keyImageSrc==''){
			keyImageSrc = &quot;/_layouts/images/prf16.gif&quot;;
		}
		// If number - trim off all spaces, commas and periods
		if($(fields[FieldInternalName]).html().match('SPFieldNumber')!=null){
			$(fields[FieldInternalName]).find(':input').keyup(function(e){
				var currVal = $(this).val();
				$(this).val(currVal.replace(/[^0-9]/g,''));
			});
		}
		
		// Determine where to put the image - if used with the Heading-script		
		if($(fields[FieldInternalName]).find(&quot;h3:has('div')&quot;).length&gt;0){
			var insertImageHere = 'h3 div';
		}else{
			var insertImageHere = 'h3';
		}
		
		// Add blur function
		$(fields[FieldInternalName]).find(':input').blur(function(){
			// Check if input value is unique in this list
			checkPrimaryKey(FieldInternalName,$(this),PrimaryKeyViolationWarning);
		})
		// Add key image before label
		.parents('tr:first').find(insertImageHere)
		.prepend(&quot;&lt;img title='&quot; + PrimaryKeyHoverImageText + &quot;' src='&quot; + keyImageSrc + &quot;'&gt;&quot;);
	}
}

function checkPrimaryKey(FIName,keyField,warningText){
wsBaseUrl = L_Menu_BaseUrl + '/_vti_bin/';
var ItemId = getIdFromFormAction(); // Returns 0 if NewForm
var keyFieldVal = keyField.val().replace(/&amp;/g,'&amp;amp;');

	if(ItemId==0){ // NewForm
		var query = &quot;&lt;Where&gt;&lt;Eq&gt;&lt;FieldRef Name='&quot; + FIName + &quot;'/&gt;&lt;Value Type='Text'&gt;&quot; + keyFieldVal + &quot;&lt;/Value&gt;&lt;/Eq&gt;&lt;/Where&gt;&quot;;
	}else{ // EditForm - skip current ID
		var query = &quot;&lt;Where&gt;&lt;And&gt;&lt;Eq&gt;&lt;FieldRef Name='&quot; + FIName + &quot;'/&gt;&lt;Value Type='Text'&gt;&quot; + keyFieldVal + &quot;&lt;/Value&gt;&lt;/Eq&gt;&quot; +
					&quot;&lt;Neq&gt;&lt;FieldRef Name='ID'/&gt;&lt;Value Type='Counter'&gt;&quot; + ItemId + &quot;&lt;/Value&gt;&lt;/Neq&gt;&lt;/And&gt;&lt;/Where&gt;&quot;;
	}
	var res = queryItems(listDisplayName,query,['ID']);
	if(res.count==-1){
		alert(&quot;An error occured in the query:n&quot; + query);
	}else if(res.count&gt;0){
		keyIsNotUniqueCount = keyIsNotUniqueCount + 1;
		keyField.parents('td:first').find(&quot;.customPrimaryKeyAlert&quot;).remove();
		keyField.parents('td:first').append(&quot;&lt;div class='customPrimaryKeyAlert' style='color:red'&gt;&quot; + warningText + &quot;&lt;/div&gt;&quot;);
	}else{
		keyField.parents('td:first').find(&quot;.customPrimaryKeyAlert&quot;).remove();
		if(keyIsNotUniqueCount&gt;0){
			keyIsNotUniqueCount = keyIsNotUniqueCount - 1;
		}
	}
	// Hide button
	if(keyIsNotUniqueCount&gt;0){
		$(&quot;input[id$='SaveItem']&quot;).hide();
	}else{
		$(&quot;input[id$='SaveItem']&quot;).show();
	}
}

// This function gets the list item ID from the form's action-attribute
function getIdFromFormAction(){
var action = $(&quot;#aspnetForm&quot;).attr('action');
var IdCheck = action.substring(action.indexOf('?')).indexOf('ID=');
	if(IdCheck==1){
	var end = action.indexOf('&amp;');
		if(action.indexOf('&amp;')&lt;0){
			id = action.substring(action.indexOf('ID=')+3);
		}else{
			id = action.substring(action.indexOf('ID=')+3,end);
		}
	}else{
		id = 0; // Called from NewForm returns 0
	}
	return id;
}

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 “PrimaryKey.js” and upload to the “script-library” as shown above.

This is not a “guaranteed” primary key, as it does not work in datasheet-editing, and I’m sure someone finds a way to trick it. I’m nevertheless confident that someone can make use of this code.

Let me know if something is unclear.

Regards
Alexander