All posts by Alexander Bautz

Return value of all SharePoint fieldtypes with Javascript

This post is old… you will find other ways to do all this in newer posts – Alexander

As promised, here are the post on returning the value of any SharePoint-field with the use of Javascript.
As for now this script is IE only! – as stated earlier, i personally do not use Firefox, and i have not had the time to try to adapt it to Firefox. The main thing that has to be done is to handle the node-issue where Firefox counts line breaks in the code as a node.

I first learned to manipulate list items with javascript here: Microsoft SharePoint Designer Team Blog, and the piece on returning radio button values is a product of this guy here: Markuso.

About the script
This script returns the value of the following SharePoint-fieldTypes

  • Single line text
  • Multiple line text (Plain text)
  • Number
  • Currency
  • Multiple choice check box
  • Date
  • Radio Button
  • Drop down
  • Yes/No
  • Hyperlink
  • Picture
  • Lookup – Single
  • Lookup – Multiple
  • Person (DisplayName or LoginName)

I always use the fields “FieldInternalName” when addressing it in code, it never changes no matter how many times you change the “DisplayName”.

The script:

<script type="text/javascript">
/*************************************************************
Type:
Singelline tekst and multiline tekst (Plain text), Number, Currency = text
Multichoice checkbox = checkbox (returns commaseparated values)
Date (returns date only, but works with both DateOnly and DateAndTime) = date
RadioButton = radio
Dropdown = dropdown
Yes/No = bool
Hyperlink or picture (returns commaseparated: description,url) = url
Lookup – single (below and over 20 items), MultiLookup (returns array) = lookup
Lookup Multiple – you can use plain ‘lookup’, but if you want only "multi" = lookupMulti
Person – DisplayName = personDisplay
Person – LoginName = personLogin
Use: var value = returnValue(‘checkbox’,’FieldInternalNameOfYourField’);
*************************************************************/
function returnValue(type, fieldInternalName) {
var arr = document.getElementsByTagName(‘!’);//get all comments
for (var i=0;i < arr.length; i++ ) {
// Date
if (type==’date’ && arr[i].innerHTML.match(‘FieldInternalName="’ + fieldInternalName + ‘"’)) {
var fieldTitle = arr[i].innerHTML.substring(arr[i].innerHTML.indexOf(‘FieldName=’)+11,arr[i].innerHTML.indexOf(‘n’)-2);
var tags = document.getElementsByTagName(‘input’);
for (var i=0; i < tags.length; i++) {
if (tags[i].title == fieldTitle && tags[i].parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.innerHTML.indexOf(‘FieldName="’+fieldTitle+’"’) > -1)
{
return tags[i].value;
}
}
// RadioButton – Credit to http://blog.markuso.com/ – slightly modified by me to use FieldInternalName
}else if(type==’radio’ && arr[i].innerHTML.match(‘FieldInternalName="’ + fieldInternalName + ‘"’)) {
var tags = document.getElementsByTagName("input");
for (var i=0; i < tags.length; i++) {
var nameString = tags[i].name;
// get selected radio button value only
if (tags[i].type == "radio") {
var tagParentHTML = tags[i].parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.innerHTML;
if (tagParentHTML.indexOf(‘FieldInternalName="’+fieldInternalName+’"’) > -1) {
var radioButtons = document.getElementsByName(nameString);
var radioValue = "";
for (var x=0; x < radioButtons.length; x++) {
if (radioButtons[x].checked) {
radioValue = radioButtons[x].parentElement.title;
break;
}
}
var o = document.createElement("INPUT");
o.type = "hidden";
o.value = radioValue;
return o.value;
}
}
}
return null;
// Checkbox
}else if(type==’checkbox’) {
var arr = [];
var arrValue = [];
var tags = document.getElementsByTagName("input");
for (var i=0; i < tags.length; i++) {
if (tags[i].type == "checkbox") {
var tagParentHTML = tags[i].parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.innerHTML;
if (tagParentHTML.indexOf(‘FieldInternalName="’+fieldInternalName+’"’) > -1) {
arr.push(tags[i].id);
}
}
}
for (var x=0; x < arr.length; x++) {
var chkBox = document.getElementById(arr[x]);
if (chkBox.checked) {
arrValue.push(chkBox.parentElement.title);
}
}
return arrValue.toString();
// Text or Dropdown
}else if((type==’text’ || type==’dropdown’) && arr[i].innerHTML.match(‘FieldInternalName="’ + fieldInternalName + ‘"’)) {
return arr[i].parentNode.childNodes[1].childNodes[0].value;
// Hyperlink or Picture
}else if(type==’url’ && arr[i].innerHTML.match(‘FieldInternalName="’ + fieldInternalName + ‘"’)) {
// returns commaseparated (description,url) so it can be split later
var hyperlink = [];
hyperlink.push(arr[i].parentNode.childNodes[1].childNodes[4].value);
hyperlink.push(arr[i].parentNode.childNodes[1].childNodes[1].value);
return hyperlink;
// Bool
}else if(type==’bool’ && arr[i].innerHTML.match(‘FieldInternalName="’ + fieldInternalName + ‘"’)) {
return arr[i].parentNode.childNodes[1].childNodes[0].checked;
// Lookup
}else if(type==’lookup’ && arr[i].innerHTML.match(‘FieldInternalName="’ + fieldInternalName + ‘"’)) {
// Under 20 items
var opt = arr[i].parentNode.childNodes[1].childNodes[0].options;
if(opt!=null) {
for (var x=0;x<opt.length;x++) {
if(opt[x].selected == true) {
return (opt[x].innerHTML);
}
}
}else if(opt==null){
if(arr[i].parentNode.childNodes[1].childNodes[0].childNodes[0]!= null) {
// Over 20 items
return arr[i].parentNode.childNodes[1].childNodes[0].childNodes[0].value;
}else{
// MultiLookup – optionally you can call the script with type=’lookupMulti’
var arrSelected = [];
var fieldId = arr[i].parentNode.childNodes[1].childNodes[0].id;
var selectResultId = fieldId.substr(0,fieldId.indexOf(‘MultiLookupPicker’)) + ‘SelectResult’;
var selectResultField = document.getElementById(selectResultId);
for(var x=0;x < selectResultField.length; x++){
arrSelected.push (selectResultField[x].innerHTML);
}
return arrSelected.toString();
}
}
}
// Lookup Multi (can also use plain ‘lookup’ as spacified above
else if(type==’lookupMulti’ && arr[i].innerHTML.match(‘FieldInternalName="’ + fieldInternalName + ‘"’)) {
var arrSelected = [];
var fieldId = arr[i].parentNode.childNodes[1].childNodes[0].id;
var selectResultId = fieldId.substr(0,fieldId.indexOf(‘MultiLookupPicker’)) + ‘SelectResult’;
var selectResultField = document.getElementById(selectResultId);
for(var x=0;x < selectResultField.length; x++){
arrSelected.push (selectResultField[x].innerHTML);
}
return arrSelected.toString();
// Person
}else if(type==’personDisplay’ && arr[i].innerHTML.match(‘FieldInternalName="’ + fieldInternalName + ‘"’)) {
var rawString = arr[i].parentNode.childNodes[1].innerHTML;
if(rawString.indexOf(‘isresolved="True"’)>0){
// user resolved OK
// Use these for DisplayName
var displayName = rawString.indexOf(‘displaytext="’);
var start = displayName + 13;
var stopp = displayName + rawString.substring(rawString.indexOf(‘displaytext="’)).indexOf(‘key="’)-2;
var user = rawString.substring(start, stopp);
return user;
}else{
// user not resolved
return "";
}
}else if(type==’personLogin’ && arr[i].innerHTML.match(‘FieldInternalName="’ + fieldInternalName + ‘"’)) {
var rawString = arr[i].parentNode.childNodes[1].innerHTML;
if(rawString.indexOf(‘isresolved="True"’)>0){
// Use these for Loginname
var loginName = rawString.indexOf(‘isresolved="True"’);
var start = loginName + rawString.substring(rawString.indexOf(‘isresolved="True"’)).indexOf(‘key="’)+5;
var stopp = loginName + rawString.substring(rawString.indexOf(‘isresolved="True"’)).indexOf(‘">’);
var user = rawString.substring(start, stopp);
return user;
}else{
// user not resolved
return "";
}
}

}
}
</script>
[/javascript]

You should now be able to return all fieldvalues from SharePoint forms.

Here’s an example of how to use it in the PreSaveAction (add this script and it will always execute between you pressing th “OK-button” and the actual save of the item:

<script type="text/javascript">
function PreSaveAction() {
var checkBoxValue = returnValue(‘checkbox’,’CheckboxesChoice’);
if(checkBoxValue.match(‘Yellow’)==null) {
alert("You did not select Yellow!nnIf you do not select Yellow, you will not be able to save this list item!");
// aborts the save process
return false;
}
// Nothing above has returned false – go through with the save process
return true;
}
</script>
[/javascript]

I will return with more on validating input with both the SharePoint function PreSaveAction and on “events” in the fields themselves.

That’s all for now.

Alexander

Find and hide fields in NewForm, DispForm and EditForm in both IE and Firefox

This post is old… you will find other ways to do all this in newer posts – Alexander

This post will talk about how to use javascript to find a form-field in av SharePoint list form (NewForm, DispForm and EditForm) from its unique FieldInternalName.

When you have found it you can do almost anything you want with it – hide it, make it readOnly, return the value of the field or validate the input. I will come back to this in future posts in this “Series”.

The method i will talk about here is not new – i believe the guys at CleverWorkarounds posted it first, or was it here – I’m not really sure (if you do know who to credit – please let me know!).

Almost everyone uses a method where they search for a field by the fields DisplayName, but this is not a very robust way of doing it as the displayName can easily be altered – and thereby breaking the script.

It has also been talked about using the Id of the field as reference – the id one would believe to be unique – but it is NOT! If you change the column order in the list form – the id changes – it has a reference to the column order in the id.

This leaves only one suitable way to reference fields – by it’s FieldInternalName.
To find the FieldInternalName you can view the source of the page and search for your DisplayName.

One thing to remember when using FieldInternalName is that it newer changes – and therefore the FieldInternalName could end up totally different from the DisplayName.

When creating fields all spaces in the fieldName will be replased with _x0020_, and special characters with its equivalent hex-code – therefore create a proper fieldname first – then edit it to add spaces and special characters. By doing this your FieldInternalName will be readable and makes sense in your code.

The script i have created uses the FieldInternalName to uniquely identify the field, but it works ONLY in Internet Explorer because it searches for a “Comment-tag” which is not recognized in Firefox as a valid HTML tag:

&lt;script type=&quot;text/javascript&quot;&gt;
function findacontrol(FieldInternalName) {
var arr = document.getElementsByTagName('!');
	for (var i=0;i &lt; arr.length; i++ ) {
		if (arr[i].innerHTML.match('FieldInternalName=&quot;' + FieldInternalName + '&quot;')) {
			if(window.location.href.indexOf('DispForm.aspx')&gt;0) {
				return arr[i].parentNode.childNodes[1];
			}else{
				return arr[i].parentNode.childNodes[1].childNodes[0];
			}
		}
	}
}
&lt;/script&gt;

I’m not using Firefox myself, but realized that it would be nice to have this work in Firefox to – almost all my scripts depends on this method of finding fields.

I therefore made a similar script that works on both browsers, but it’s not as sleek as the one for IE only.

The main reason it has to be different is that Firefox does not recognize <!– the comment- tag –>[/javascript] as a valid HTML tag and therefore one have to use the td-tag to search the code. The disadvantage of this approach is that there are far more td-tags than comments in the code and it must loop trough more code in the hunt for “your field”.

One other thing Firefox does different than IE, is childNodes and nextSibling. Firefox treats line breaks in the code as a node and therefore the depth of childNodes in the script must be different for the two.

Script for both IE and Firefox:

<script type="text/javascript">
function findacontrolCrossBrowser(FieldInternalName) {
var arr = document.getElementsByTagName(‘td’);
for (var i=0;i < arr.length; i++ ) {
if (arr[i].innerHTML.match(‘FieldInternalName="’ + FieldInternalName + ‘"’) && arr[i].className == ‘ms-formbody’) {
if(window.location.href.indexOf(‘DispForm.aspx’)>0) {
return arr[i].parentNode.childNodes[1];
}else{
if(arr[i].childNodes[1].nodeType==1) {
// Assumes it is IE
return arr[i].childNodes[1].childNodes[0];
}else if(arr[i].childNodes[1].nodeType==8) {
// Assumes it is Firefox
return arr[i].childNodes[3].childNodes[0];
}
}
}
}
}
</script>
[/javascript]

How to add webPart to NewForm, DispForm or EditForm? Click here.

One possible use of this script is to hide a single field, or a field array:

function hideFieldsArray() {
var array = [‘Field1’, ‘Field2’];
for (x in array)
{
xField = findacontrolCrossBrowser(array[x]);
if(xField!=null)
{
if(window.location.href.indexOf(‘DispForm.aspx’)>0)
{
xField.parentNode.parentNode.style.display="none";
}else{
xField.parentNode.parentNode.parentNode.style.display="none";
}
}
}
}
</script>
[/javascript]

A fully functional setup of this script would be to add a CEWP below the form in for instance NewForm.aspx, and add the following script to it – of course change ‘Field1’ and ‘Field2’ with your FieldInternalName:

&lt;script type=&quot;text/javascript&quot;&gt;
hideFieldsArray();

function hideFieldsArray() {
var array = ['Field1', 'Field2'];
for (x in array)
{
xField = findacontrolCrossBrowser(array[x]);
	if(xField!=null)
		{
			if(window.location.href.indexOf('DispForm.aspx')&gt;0)
			{
				xField.parentNode.parentNode.style.display=&quot;none&quot;;
			}else{
				xField.parentNode.parentNode.parentNode.style.display=&quot;none&quot;;
			}
		}
	}
}

function findacontrolCrossBrowser(FieldInternalName) {
var arr = document.getElementsByTagName('td');
	for (var i=0;i &lt; arr.length; i++ )  {
		if (arr[i].innerHTML.match('FieldInternalName=&quot;' + FieldInternalName + '&quot;') &amp;&amp; arr[i].className == 'ms-formbody') {
			if(window.location.href.indexOf('DispForm.aspx')&gt;0) {
				return arr[i].parentNode.childNodes[1];
			}else{
				if(arr[i].childNodes[1].nodeType==1) {
					// Assumes it is IE
					return arr[i].childNodes[1].childNodes[0];
				}else if(arr[i].childNodes[1].nodeType==8) {
					// Assumes it is Firefox
					return arr[i].childNodes[3].childNodes[0];
				}
			}
		}
	}
}
&lt;/script&gt;

You can also call scripts on pageLoad with:

<script type="text/javascript">
_spBodyOnLoadFunctionNames.push("functionName");
</script>
[/javascript]
but then the hiding of the fields will happen after the page has been presented to the use, and will result in a seconds flash of all your “hidden fields” – not good.

I will return with more on how to return the value from almost all field types (Single line of text, Multiple lines of text (Plain text), Choice (dropdown, radio and multi choice), Date and Time, Lookup, Yes/No, Person or Group), how to use and validate the input, and how to dynamically collapse or expand fields based on selections in other fields.

Stay tuned!

Alexander

Compare DueDate with Today in list view

15.09.2009: Complete rewrite of the script to tidy up the code, improve functionality, and to add jQuery-logic to make it run smoother.

This script is used to Compare a “DueDate” in a list view with “Today” and generate “traffic lights” to flag status. It also adds a mouseover tooltip that shows the list element’s “day, hour and minute – status”.

The end result looks like this:
IMG

You can filter on the “Status-column”:
IMG

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

Add a CEWP to your list view – below the list form, and add this code:

<script type="text/javascript" src="/test/English/Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript" src="/test/English/Javascript/trafficLightsOnDueDate.js"></script>
<script type="text/javascript">
// Offset
yOffsetMinutes = 2880; // When to show the yellow "flag"
rOffsetMinutes = 1440; // when to show the red "flag"

// Order of apperance of the dateFields in your Formula (1 = first position, 2 = second position and 3 = third position)
OrderDay = 2;
OrderMonth = 1;
OrderYear = 3;

// Settings
defaultTimeIfDateOnly = '12:00'; // If used with "Date Only" - what time should be used as "DueTime" - Military Time
splitChar = '/'; // The separator between the day month year of your calculated dateField: 01[splitChar]01[splitChar]2009
separatorDateTime = ' '; // The separator in the calculated column between date and time: 01/01/2009[separatorDateTime]08:00
LeadInTextBeforeDate = 'Due:'; // The leadin text of your calculated dateField - used to locate the correct table cells

// Tooltip on "traffic lights" before days/hours/minutes
TooltipDueIn = 'Due in: '; 
TooltipOverdue = 'Overdue: ';

// Tooltip on "traffic lights" after days/hours/minutes
TooltipDays = ['day','s']; // Array - first value for "singular", second for "plural"
TooltipHours = ['hour','s']; // Array - first value for "singular", second for "plural"
TooltipMinutes = ['minute','s']; // Array - first value for "singular", second for "plural"

// Call script 
trafficLightsOnDueDate();
</script>

Like this:
IMG

The script “trafficLightsOnDueDate.js” has this soursecode:

/* Compare DueDate with Today in list view and generate "traffic lights" from DueDate
* ----------------------------------------------------
* Author: Alexander Bautz
* alexander.bautz@gmail.com
* Version: 2.0
* LastMod: 15.09.2009
* ----------------------------------------------------
* Must include reference to jQuery
* ----------------------------------------------------
*
* All variables are defined in a CEWP below the list view of your list. See separate codeblock for code.
*
* ----------------------------------------------------
*/

function trafficLightsOnDueDate() {
// Find today's date
var now = new Date();
$("td.ms-vb2:contains('" + LeadInTextBeforeDate + "')").each(function(){
	var sepDate = '';
	var sepHourMinutes = '';
	if($(this).text().substring(LeadInTextBeforeDate.length + 1).length>10){
		sepDate = $(this).text().substring(LeadInTextBeforeDate.length + 1,$(this).text().lastIndexOf(separatorDateTime)).split(splitChar);
		sepHourMinutes = $(this).text().substring($(this).text().lastIndexOf(separatorDateTime)+separatorDateTime.length).split(':');
		IncludeHoursAndMinutes = true;
	}else{
		sepDate = $(this).text().substring(LeadInTextBeforeDate.length + 1).split(splitChar);
		IncludeHoursAndMinutes = false;
	}		

	var m = sepDate[OrderMonth - 1];
	var d = sepDate[OrderDay - 1];
	var y = sepDate[OrderYear - 1];
	
	if(IncludeHoursAndMinutes){
		h = sepHourMinutes[0];
		min = sepHourMinutes[1];
	}else{	
		h = defaultTimeIfDateOnly.split(':')[0]
		min = defaultTimeIfDateOnly.split(':')[1]
	}
	// Build the datestring from fieldvalue
	var fieldDate = new Date(y,m-1,d,h,min,00);

	// Build friendly string for due/overdue mouseover tooltip
		var DueByDays = msToDHM(Math.round((fieldDate.getTime() - now.getTime())));
		var overDueByDays = msToDHM(Math.round((now.getTime() - fieldDate.getTime())));
	
	// OffsetDate - Create the traffic lights
	var yellowOffsetDate = now.getTime() + (yOffsetMinutes * 60000);
	var redOffsetDate = now.getTime() + (rOffsetMinutes * 60000);
	
		if(yellowOffsetDate < fieldDate.getTime() && redOffsetDate < fieldDate.getTime()){
		// green
			$(this).html("<div style='font-weight:bold; font-size:16px; color:green'>•</div>");
			$(this).parent().attr('title',TooltipDueIn + DueByDays);
		}
		else if(yellowOffsetDate >= fieldDate.getTime() && redOffsetDate < fieldDate.getTime()){
		// yellow
			$(this).html("<div style='font-weight:bold; font-size:16px; color:yellow'>•</div>");
			$(this).parent().attr('title',TooltipDueIn + DueByDays);
		}		
		else if(redOffsetDate > fieldDate.getTime() && now.getTime() < fieldDate.getTime()){
		// red due in...
			$(this).html("<div style='font-weight:bold; font-size:16px; color:red'>•</div>");
			$(this).parent().attr('title',TooltipDueIn + DueByDays);
		}
		else if(redOffsetDate > fieldDate.getTime() && now.getTime() > fieldDate.getTime()){
			// red overdue by...
			$(this).html("<div style='font-weight:bold; font-size:16px; color:red'>•</div>");
			// Red text in all row (but the title with link)
			$(this).parent().attr('title',TooltipOverdue + overDueByDays).find('td').addClass('ms-errorcolor ms-bold');
		}

	});
}

function msToDHM(ms){
	var countDays = Math.floor(ms / 86400000); // 86400000 in one day
	var countHours = Math.floor((ms % 86400000) / 3600000); // Find "leftovers" after all the full days have been taken away / 3600000 ms in one hour
	var countMinutes = Math.floor(((ms % 86400000) % 3600000) / 60000); // Find "leftovers" after all hours have been taken away / 60000 ms in one minute
	var str = '';
	if(countDays!=0){
		if(countDays>1){
			str +=  countDays + " " + TooltipDays[0] + TooltipDays[1] + " ";
		}else{
			str +=  countDays + " " + TooltipDays[0] + " ";
		}	
	}
	if(countHours!=0){
		if(countHours>1){
			str += countHours + " " + TooltipHours[0] + TooltipHours[1] + " ";
		}else{
			str += countHours + " " + TooltipHours[0] + " ";
		}
	}
	if(countMinutes!=0){
		if(countMinutes>1){
			str +=  countMinutes + " " + TooltipMinutes[0] + TooltipMinutes[1];
		}else{
			str +=  countMinutes + " " + TooltipMinutes[0];
		}
	}
	if(countDays + countHours + countMinutes == 0)str += " 0 " + TooltipMinutes[0] + TooltipMinutes[1]
	return str;
}

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

Add these columns to your list:

  • a column of type “Date and Time”, format “Date Only” or “Date & Time” named DueDate
  • a column of type “Yes/No (check box)” named Completed
  • a column of type “Calculated (calculation based on other columns)” named Status

The DueDate-column does not have to be in the list view, but the calculated column must be.

The column named Status has this formula for “DateOnly”:

=IF(DueDate="","N/A",IF(Completed<>TRUE,"Due: "&TEXT(DueDate,"mm/dd/yyyy"),"Completed"))

And this formula for “Date & Time”:

=IF(DueDate="","N/A",IF(Completed<>TRUE,"Due: "&TEXT(DueDate,"mm/dd/yyyy HH:mm"),"Completed"))

This has formula for “Date & Time”:
IMG

Thats it!

Alexander

Welcome to my blog!

Welcome!

You find newly added posts on the right side of the screen. All previously posts are found in the “Archives”, and you can search for keywords in the top right corner of the front page.

How to post code in comments
How to troubleshoot when the scripts does not work
How to use these scripts in a customized form

I have added a Copyright and disclaimer notice here.

Requests are posted in the Request’s post.

Regards
Alexander