Welcome to my blog!

November 26, 2008 by Alexander

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.

Requests are posted in the Request’s post.

Regards
Alexander

Expand empty subgroups and remove group header in grouped list view

February 6, 2010 by Alexander

I got this request from Kale:

Do you have an ideas on how to remove “empty/blank” items when using the “group by” feature? See the example below. In other words, for category ‘Test 1′ you have to expand the blank item just to see the documents since they don’t have any subcategories assigned to them.

Example:
* Category: Test 1
* Subcategory 1:
– Document 1
– Document 2
* Category: Test 2
* Subcategory: SharePoint
– Document 3
– Document 4
* Subcategory: CRM
– Document 5
– Document 6

This is how I want it to work:
* Category: Test 1
– Document 1
– Document 2
* Category: Test 2
* Subcategory: SharePoint
– Document 3
– Document 4
etc.

Thanks!
Kale

This script checks if the “groupBy” is empty, and if so, expands the content of the group and hides the group header.

Add this script in a CEWP below the list view – alter the location of jQuery to reflect your location:

<script type="text/javascript" src="../../Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
	// Add onclick to the first grouping
	$(".ms-listviewtable td.ms-gb").click(function(){
		expandEmptyCategory();
	});
	// Call function on load
	isTbodyLoaded();
});

var isloadedCheck = 0;
// Looping function to call "expandEmptyCategory" when subgroups are loading - looping every 200ms for a maximum of 4 seconds
function isTbodyLoaded(){
	setTimeout(function(){
		tbodyIsLoadedLength = $(".ms-listviewtable tbody[isLoaded='true']").length;
		if(tbodyIsLoadedLength>0){
			expandEmptyCategory();
		}else{
			isloadedCheck += 1;
			if(isloadedCheck<=20){
				isTbodyLoaded();
			}
		}
	},200);
}

function expandEmptyCategory(){
var NameGrouping2 = $(".ms-listviewtable td.ms-gb2:first a:eq(1)").text();
	$(".ms-listviewtable td.ms-gb2").each(function(){
		var grNameRaw = $(this).text().replace(NameGrouping2+' :','');
		grName = grNameRaw.substring(0,grNameRaw.indexOf('(')-1).replace(/\s|\xA0/g,'');
		if(grName.length==0){
		var parentTbody = $(this).parents('tbody:first');
			if(parentTbody.css('display')!='none'){
			var tIdRaw = parentTbody.attr('id');
			var tId = tIdRaw.substring(4);
			var tb = $("#tbod"+tId+"_");
				if(tb.attr('isLoaded')){
					if(tb.css('display')=='none'){
						$(this).find('a:first').click();
						$(this).parents('tbody:first').hide();
					}else{
						$(this).parents('tbody:first').hide();
					}
				}
			}
		}
	});
}
</script>

This solution is not fully tested so please post any bugs you might find.

Alexander

SharePoint form: present fields side-by-side

January 28, 2010 by Alexander

I got this request from Khan:

Alexander,
… Another question I have is how I can display two fields (and their labels) in the same row? I know I am asking too much. But I really hope you can give me some advice o this. Thanks man.

Here is an image of a few random fields put side-by-side:
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.

Add a CEWP below your NewForm/DispForm/EditForm with 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/FieldsSideBySide.js"></script>
<script type="text/javascript">
  // Append fields to the field "User"
  arrToPutSideBySide = ['StartTime','EndTime'];
  customSideBySide(arrToPutSideBySide,'User');
  // Appends another set of fields to the field "User"
  arrToPutSideBySide = ['FirstName','MiddleName','LastName'];
  customSideBySide(arrToPutSideBySide,'User');

  // To append the fields to the top use this code:
  //arrToPutSideBySide = ['FirstName','MiddleName','LastName'];
  //customSideBySide(arrToPutSideBySide,'',true);
</script>

This code is not the full code from the screenshot above. Each horizontal “section” is made with a separate call to the function “customSideBySide()”.

Parameters explained:

  • arr: Array or fields to put in one line.
  • insertAfterField: If you want to append the fields below another field, insert the FieldInternalName here. Set this parameter to “” if you want to use the next parameter.
  • appendToTop: To insert the fields in the top of the form, set it to true. To insert at the bottom of the form, set it to false.

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

/* Sharepoint form: Present fields side-by-side
 * ---------------------------------------------
 * Created by Alexander Bautz
 * alexander.bautz@gmail.com
 * http://sharepointjavascript.wordpress.com
 * v1.0
 * LastMod: 26.01.2010
 * ---------------------------------------------
 * Must include reference to:
 *  jQuery - http://jquery.com
 * ---------------------------------------------
*/

function customSideBySide(arr,insertAfterField,appendToTop){
if(typeof(fields)=='undefined')fields = init_fields();
// Does the field specified as "insertAfterField" exist?
if(insertAfterField!='' && typeof(fields[insertAfterField])=='undefined'){
	alert("The FieldInternalName \"" + insertAfterField + "\", which is specified as \"insertAfterField\" does not exist.");
	return false;
}
	var str = '';
	$.each(arrToPutSideBySide,function(i,fin){
		// Check if FieldInternalName is correct
		if(typeof(fields[fin])=='undefined'){
			alert("The FieldInternalName \"" + fin + "\" does not exist.");
			return false;
		}
		// Adapt width of single line and multi lines of text
		if($(fields[fin]).html().indexOf('FieldType="SPFieldText"')>0){
			$(fields[fin]).find('input').css({'width':'100%'});
		}else if($(fields[fin]).html().indexOf('FieldType="SPFieldNote"')>0){
			$(fields[fin]).find('textarea').css({'width':'100%'});
		}
		var tdWidth = Math.round(100/arr.length);
		str += "<td class='ms-formbody' style='width:"+tdWidth+"%'>" + $(fields[fin]).find('.ms-formlabel').html() + $(fields[fin]).find('.ms-formbody').html() + "</td>";
		// Remove original field
		$(fields[fin]).remove();
	});
	str = "<tr><td colspan='2'><table cellpadding='0' cellspacing='0' style='width:100%'><tr>" + str + "</tr></table></td></tr>";
	if(insertAfterField!=''){
		$(fields[insertAfterField]).after(str);
	}else{
		if(appendToTop){
			$("table.ms-formtable tbody:first").prepend(str);
		}else{
			$("table.ms-formtable tbody:first").append(str);
		}
	}
}

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

Ask if something is unclear.

Regards
Alexander

How to use these scripts in a customized form

January 25, 2010 by Alexander

This article describes how to use most of the solutions found in this blog with a customized form. The scripts which this article addresses, is the ones involving the function “init_fields()”.

This was originally an answer to a comment in one of the articles.


I get this question a lot:
How can i use these scripts in a customized form?

The answer is simple, but i will explain it so that you understand why it’s not working.

This script relays in the function init_fields() to identify and “objectify” the form by it’s <TR> tags (table rows). What the function does is to find all the FieldInternalNames in the code by this “information-tag”:

<!-- FieldName="This is the DisplayName"
FieldInternalName="ThisIsTheFieldInternalName"
FieldType="SPFieldText"
-->

It then make an object which, when called with the FieldInternalName of a field, returns an object containing that table row (both formlabel and formtable).

When initiated like this:

fields = init_fields();

You address a <TR> like this:

$(fields[FieldInternalName])

Where “FieldInternalName” is the FieldInternalName of your field. Read here how to identify the FieldInternalName.

This is the original function for use in standard SharePoint forms:

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

Customized form
When you modify the list form in SharePoint Designer, you loose the FieldInternalName and therefore the function init_fields() does not return anything.

To address the fields on a custom form you have to find another way of addressing these fields and to “objectify” them in the same way as the script init_fields(). Basically you could insert some kind of “identifier-attribute” on the <TR> tags, or you can go with the displayName – only remember that if you change the displayName – you have to update your script…

To use the “displayName”, replace the init_fields() function with this one:

function init_fields(){
  var res = {};
  $("td.ms-formlabel h3.ms-standardheader").each(function(){
  var str = $.trim($(this).text().replace(/\*/g,''));
	  res[str] = $(this).parents('tr:first');
  });
  return res;
}

This approach finds the displayName by searching for an <h3> tag with class “ms-standardheader”. Modify this “identifier” to match your modified form.

Ask if anything is unclear.

Regards
Alexander

SharePoint form: scroll to field as with an anchor tag

January 24, 2010 by Alexander

I got this request from Cookie:

Is there a way to create an anchor within a NewForm or EditForm? I have a long intake, or it could be long. When I assign the the item to an owner and provide them a link to the form, it would be easier to have an addition to the link with the anchor that links to a specific field in the form. Maybe a script that uses the fieldinternalname and converts that to the anchor name for simplicity.

Place this code in a CEWP below the form in NewForm, EditForm or DispForm:

<script type="text/javascript" src="../../Javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
/*
  This script is used to be able to scroll to a field based upon a url query string parameter like this:
  .../EditForm.aspx?ID=1&focus=FieldInternalNameOfFieldToFocusOn
*/

fields = init_fields();

// If the query string parameter "focus" is set, and a field with that FieldInternalName is found, scroll to that field
$(document).ready(function(){
	var q = getQueryParameters();
	if(q['focus']!=undefined){
		var fin = q['focus'];
		if(fields[fin]!=undefined){
			var offset = $(fields[fin]).offset();
			scrollTo(0,offset.top);
		}
	}
});

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

// Function to make an object of all tr-tags in the form
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;
}
</script>

Make your links up like this:
…/EditForm.aspx?ID=1&focus=FieldInternalNameOfFieldToFocusOn

Look here on how to find the FieldInternalName of your field.

Regards
Alexander