DataFormWebPart – create your pagination

DataFormWebPart is simple to be customized if you edit it with SharePoint Designer from design view. But on 2013 version, design view was removed. So it is time to learn how to customize the webpart from the code. And one of the things a developer might be required to do is to create a pagination.

Now, let’s start creating the skeleton of the dataformwebpart.

<WebPartPages:DataFormWebPart runat="server" IsIncluded="True" FrameType="None" NoDefaultStyle="TRUE" ViewFlag="0" Title="" __markuptype="vsattributemarkup" __WebPartId="{1B724E2D-207A-4F03-A851-7DA57139C01B}" id="PMView" showwithsampledata="true" __AllowXSLTEditing="true" WebPart="true" Height="" Width="">
<DataSources>
</DataSources>
<ParameterBindings>
</ParameterBindings>
<XSL>
</XSL>
</WebPartPages:DataFormWebPart>

So we have all the sections for the webpart. Now we will add information to each section.

Add the datasource

<SharePoint:SPDataSource runat="server" DataSourceMode="List" SelectCommand="&lt;View&gt;&lt;/View&gt;" UseInternalName="True" ID="MyDataSource"><SelectParameters>
<WebPartPages:DataFormParameter ParameterKey="dvt_sortfield" PropertyName="ParameterValues" Name="dvt_sortfield" DefaultValue="ID" /><WebPartPages:DataFormParameter ParameterKey="dvt_sortdir" PropertyName="ParameterValues" Name="dvt_sortdir" DefaultValue="FALSE" />
<asp:parameter DefaultValue="MyList" Name="ListName" />
<asp:parameter DefaultValue="0" Name="StartRowIndex" />
<asp:parameter DefaultValue="" Name="nextpagedata" />
<asp:parameter DefaultValue="30" Name="MaximumRows" />
</SelectParameters>
</SharePoint:SPDataSource>

You can notice some select parameters:

– ListName – representing the name of the list you want to display;
– StartRowIndex – starting row from where select statement begins;
– nextpagedata – data for the next page, if exists (if not is empty);
– MaximumRows – numbers of rows per page.

Add ParameterBindings section

<ParameterBinding Name="dvt_firstrow" Location="QueryString(FirstRow)" DefaultValue="1"/>
<ParameterBinding Name="dvt_nextpagedata" Location="Postback;Connection"/>
<ParameterBinding Name="dvt_startposition" Location="QueryString(Start)" DefaultValue=""/>
<ParameterBinding Name="Qs" Location="ServerVariable(QUERY_STRING)" DefaultValue=""/>
<ParameterBinding Name="CurrentPageUrl" Location="ServerVariable(URL)" DefaultValue=""/>

Add XSLT code

<xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" version="1.0" exclude-result-prefixes="xsl msxsl ddwrt" xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:SharePoint="Microsoft.SharePoint.WebControls" xmlns:ddwrt2="urn:frontpage:internal">
	
<xsl:output method="html" indent="no"/>
<xsl:decimal-format NaN=""/>
<xsl:param name="dvt_sortfield" />
<xsl:param name="dvt_sortdir" />
<xsl:param name="PageSize">30</xsl:param>
<xsl:param name="dvt_firstrow" />
<xsl:param name="dvt_nextpagedata" />	
<xsl:param name="dvt_startposition" />
<xsl:param name="Qs" />
<xsl:param name="CurrentPageUrl" />
<xsl:param name="FullPath">
	<xsl:choose>
	<xsl:when test="$Qs = ''"><xsl:value-of select="$CurrentPageUrl" disable-output-escaping="yes" /></xsl:when>
	<xsl:otherwise><xsl:value-of select="concat($CurrentPageUrl,'?',$Qs)" disable-output-escaping="yes" /></xsl:otherwise>
	</xsl:choose>
</xsl:param>

<xsl:template match="/" xmlns:x="http://www.w3.org/2001/XMLSchema" xmlns:d="http://schemas.microsoft.com/sharepoint/dsp" xmlns:asp="http://schemas.microsoft.com/ASPNET/20" xmlns:__designer="http://schemas.microsoft.com/WebParts/v2/DataView/designer" xmlns:SharePoint="Microsoft.SharePoint.WebControls">

<table>
<thead>
	<tr>
	<th>ID</th>
	<th>Title</th>
	</tr>
</thead>
<tbody>
      <xsl:for-each select="/dsQueryResponse/Rows/Row">
	<tr>
	<td><xsl:value-of select="@ID" /></td>
	<td><xsl:value-of select="@Title" /></td>
	</tr>
      </xsl:for-each>
</tbody>
<tfoot>
<tr>
<td colspan="2">

<!-- Start of Pagination -->
	<xsl:if test="$dvt_nextpagedata != '' or $dvt_firstrow &gt; 1">
<table cellpadding="0" cellspacing="0" border="0">
	<tr>
	<td style="padding:2px 2px 2px 2px;">
	<!-- Previous Page Link -->
	<xsl:if test="$dvt_firstrow &gt; 1">
	<!-- Calculate data for previous page -->
	<xsl:variable name="PreviousID" select="/dsQueryResponse/Rows/Row/@ID[position() = 1]" />
	<xsl:variable name="PreviousPos" select="$dvt_firstrow - $PageSize" />
	<xsl:variable name="PreviousPageData" select="concat('Paged=TRUE&amp;PagedPrev=TRUE&amp;p_ID=',$PreviousID)" />
	<img src="/_layouts/1033/images/prev.gif" alt="Previous page" style="border:0;cursor:pointer;" onclick="javascript:Paginate('{$PreviousPos}','{$PreviousPageData}');" />
	</xsl:if>
	</td>
	<td style="padding:2px 2px 2px 2px; font-family:Arial, Helvetica, sans-serif; font-size:12px; vertical-align:middle;">
	<xsl:value-of select="$dvt_firstrow" disable-output-escaping="yes" /> - <xsl:value-of select="$dvt_firstrow + $PageSize - 1" />
	</td>
	<td style="padding:2px 2px 2px 2px;">
	<!-- Link to next page -->
	<xsl:if test="$dvt_nextpagedata != ''">
	<xsl:variable name="NextPos" select="$dvt_firstrow + $PageSize" />
	<img src="/_layouts/1033/images/next.gif" alt="Next" style="border:0;cursor:pointer;" onclick="javascript:Paginate('{$NextPos}','{$dvt_nextpagedata}');"  />
	</xsl:if>
	</td>
	</tr>
</table>
</xsl:if>
<!-- End of Pagination -->

</td>
</tr>
</tfoot>
</table>
</xsl:template>

</xsl:stylesheet>

Add JavaScript for going to next or previous page

function Paginate(firstrow,start) {

        JSRequest.EnsureSetup() ;
	var FilePath = JSRequest.PathName;
	window.top.location.href = FilePath + '?&FirstRow=' + escapeProperly(firstrow) + '&Start=' + escapeProperly(start);
 }

Please not that JSRequest and escapeProperly are included in SharePoint client code.

If you complete each section as I described, you will have an working pagination which is set from querystrings parameters.

Advertisements

Getting controls values from a custom list form

As SharePoint is built on ASP.NET 3.5 technology, it is acting like an ASP.NET WebForm and generates long ID property for each control placed on the page. The difficulty is to control the ID in order to manipulate form elements on client side with JavaScript. Here is a little code I wrote and can be used for didactical purpose and extended.
First thing I would do is to create a namespace where I should put the objects. This is simple to achieve, as SharePoint already incorporates MicrosoftAjax.js library. So if is already there, why should not use it?

Type.registerNamespace("SHP");

Again with a help from MicrosoftAjax.js, I will create an object called “UI” (from User Interface).

SHP.UI = function() {}

I will add methods to my object to be accessed like static methods. First we will start with helper methods, which are supposed to be internal and not to be used directly in your code.

SHP.UI._GetControlsLen = function(index) { 
	/// <summary>Get numbers of controls in a form. Not intended to be used directly in your code</summary>
	/// <param name="index" type="Integer">Index of HTML form.</param>
	return document.forms[index].elements.length; 
}

SHP.UI.GetElementById = function(elementId) {	
	/// <summary>Get form by a substring contained in ID property.</summary>
	/// <param name="elementId" type="String">Portion of ID we are searching for.</param>
	for(var f = 0; f < document.forms.length; f++) {
		for(var i = 0;i < this._GetControlsLen(f); i++) {
			var control = document.forms[f].elements[i];
			if(control.id.indexOf(elementId) != -1) {
				return control;
			}
		}		
	}
	return null;
}

SHP.UI._GetCheckBoxListValues = function(elementId) {
	/// <summary>Get values from checkbox list.</summary>
	/// <param name="elementId" type="String">Portion of ID we are searching for.</param>

	var checkedValues = new Array();
	var labels = document.getElementsByTagName('LABEL');
	for(var i = 0; i < labels.length; i++) {
		var label = document.getElementsByTagName('LABEL')[i];
		var forProperty = label.getAttribute('for');
		if(forProperty) {
			if(forProperty.indexOf(elementId) != -1) {
				var checkBox = document.getElementById(forProperty);
				if((checkBox.checked == true) && (checkBox.type == 'checkbox')) {
					checkedValues.push(label.innerHTML.toString());
				}
			}
		}
	}
	if(checkedValues.length == 0) {
		return checkedValues;
	}
	else {
		return  checkedValues.join(';#');
	}
}





SHP.UI._GetValueByType = function(form_control,seachedId) {
	/// <summary>Gets the value of the control, depending on type.</summary>
	/// <param name="form_control" type="HTMLElement">Form control.</param>
	/// <param name="seachedId" type="String">Substring we search in ID.</param>

	var control_type = (control !==  null) ? form_control.type : null;
	
	switch(control_type) {
		// input text
		case 'text':              
			return form_control.value.toString();
			
		// textarea
		case 'textarea':
			return form_control.value.toString();
			
		// input hidden
		case 'hidden':
			return form_control.value.toString();
			
		// input password
		case 'password':
			return form_control.value.toString();
			
		// select control accepting single selection
		case 'select-one':
			if(form_control.options.length == 0) {
				return '';
			}
			else {
				return form_control.options[form_control.selectedIndex].value.toString();
			}
			
		// select control accepting multiple selections
		case 'select-multiple':
			var selectedValues = new Array();
			for(var i = 0; i < form_control.options.length;i++) {
				if(form_control.options[i].selected == true) {
					selectedValues.push(form_control.options[i].value.toString());
				}
			}
			if(selectedValues.length ==0 ) { return 0; } else { return selectedValues.join(';#;#') };
			
		// form checkbox list
		case 'checkbox':
			return SHP.UI._GetCheckBoxListValues(searchedId);
		default: 
			return '';
	}
}

Now is time to create final method to get the value of a control and finalize the class.

SHP.UI.GetControlValue = function(elementId) {
	var control = this.GetElementById(elementId);
	return this._GetValueByType(control,elementId);
}

SHP.UI.registerClass("SHP.UI");

Usage is simple. For example, you have a control with ID containing “TicketTitle”. Calling method SHP.UI.GetControlValue(“TicketTitle”) will return the value of it. In case is not visible on the form, as some conditional formatting can be applied, an empty string is returned.

And now, all lines together. Extend the code and/or share your ideas with me.

Type.registerNamespace("SHP");

SHP.UI = function() {}
SHP.UI._GetControlsLen = function(index) { 
	/// <summary>Get numbers of controls in a form. Not intended to be used directly in your code</summary>
	/// <param name="index" type="Integer">Index of HTML form.</param>
	return document.forms[index].elements.length; 
}
SHP.UI.GetElementById = function(elementId) {	
	/// <summary>Get form by a substring contained in ID property.</summary>
	/// <param name="elementId" type="String">Portion of ID we are searching for.</param>
	for(var f = 0; f < document.forms.length; f++) {
		for(var i = 0;i < this._GetControlsLen(f); i++) {
			var control = document.forms[f].elements[i];
			if(control.id.indexOf(elementId) != -1) {
				return control;
			}
		}		
	}
	return null;
}

SHP.UI._GetCheckBoxListValues = function(elementId) {
	/// <summary>Get values from checkbox list.</summary>
	/// <param name="elementId" type="String">Portion of ID we are searching for.</param>

	var checkedValues = new Array();
	var labels = document.getElementsByTagName('LABEL');
	for(var i = 0; i < labels.length; i++) {
		var label = document.getElementsByTagName('LABEL')[i];
		var forProperty = label.getAttribute('for');
		if(forProperty) {
			if(forProperty.indexOf(elementId) != -1) {
				var checkBox = document.getElementById(forProperty);
				if((checkBox.checked == true) && (checkBox.type == 'checkbox')) {
					checkedValues.push(label.innerHTML.toString());
				}
			}
		}
	}
	if(checkedValues.length == 0) {
		return checkedValues;
	}
	else {
		return  checkedValues.join(';#');
	}
}

SHP.UI._GetValueByType = function(form_control,seachedId) {
	/// <summary>Gets the value of the control, depending on type.</summary>
	/// <param name="form_control" type="HTMLElement">Form control.</param>
	/// <param name="seachedId" type="String">Substring we search in ID.</param>

	var control_type = (control !==  null) ? form_control.type : null;
	
	switch(control_type) {
		// input text
		case 'text':              
			return form_control.value.toString();
			
		// textarea
		case 'textarea':
			return form_control.value.toString();
			
		// input hidden
		case 'hidden':
			return form_control.value.toString();
			
		// input password
		case 'password':
			return form_control.value.toString();
			
		// select control accepting single selection
		case 'select-one':
			if(form_control.options.length == 0) {
				return '';
			}
			else {
				return form_control.options[form_control.selectedIndex].value.toString();
			}
			
		// select control accepting multiple selections
		case 'select-multiple':
			var selectedValues = new Array();
			for(var i = 0; i < form_control.options.length;i++) {
				if(form_control.options[i].selected == true) {
					selectedValues.push(form_control.options[i].value.toString());
				}
			}
			if(selectedValues.length ==0 ) { return 0; } else { return selectedValues.join(';#;#') };
			
		// form checkbox list
		case 'checkbox':
			return SHP.UI._GetCheckBoxListValues(searchedId);
		default: 
			return '';
	}
}

SHP.UI.GetControlValue = function(elementId) {
	var control = this.GetElementById(elementId);
	return this._GetValueByType(control,elementId);
}

SHP.UI.registerClass("SHP.UI");

JavaScript – check if string ends with …

In my previous post, I wrote an example how to check if a string is starting with a prefix. Now it is time to figure out how to check if a string ends with a suffix.

String.prototype.endWith = function string$endWith(suffix, caseSensitive) {
    var _caseSensitive = (typeof(caseSensitive) !== 'boolean') ? false : caseSensitive;
	if(_caseSensitive === true) {
		 return (this.substring(this.length - suffix.length) === suffix);
	}
	else {
		 return (this.substring(this.length - suffix.length).toLowerCase() === suffix.toLowerCase());
	}
}

Case sensitivity is taken into consideration if second parameter is true. If not, case sensitivity is ignored.

JavaScript – check if string starts with

Here is a simple method to check is a string is starting with a prefix.

String.prototype.beginWith = function string$beginWith(prefix, caseSensitive) {
	var _caseSensitive = (typeof(caseSensitive) !== 'boolean') ? false : caseSensitive;
	if(_caseSensitive === true) {
		return (this.substr(0, prefix.length) === prefix);
	}
	else {
		return (this.substr(0, prefix.length).toLowerCase() === prefix.toLowerCase());
	}	
}

Function is accepting two parameters. First one is the prefix we want to check if is placed on the beginning of the string and the second one is a Boolean parameter to specify if comparison is case sensitive or not. If is not specify or is not a Boolean value, it is considered to be false. Usage is simple and can be used anywhere in the code where a variable is a string type.

var mystring  = 'mytext123456789text';
mystring.beginWith('mytext') // returns true;
mystring.beginWith('Mytext', true) // returns false;