Displaying extremely large strings in a Flex DataGridColumn

Recently while working on InMarket, I was tasked with displaying very large strings within a DataGridColumn to our users. The variableRowHeight property of a DataGrid will get you part of the way, but if you start to exceed a few thousand characters, you’ll find that your row has a height larger then your entire DataGrid! As a way around this we ended up using the itemEditor capabilities of the DataGrid.

To start off, first we created an itemRenderer for the DataGridColumn, which displays a maximum number of characters. If the maximum number of characters is exceeded the itemRenderer automatically truncates the string and adds “… Read More” to it.

package
{
	import com.adobe.utils.StringUtil;
	import flash.text.StyleSheet;
	import mx.controls.dataGridClasses.DataGridItemRenderer;
 
	public class PartialTextDataGridItemRenderer extends DataGridItemRenderer
	{
		private static const MAXIMUM_NUMBER_OF_CHARACTERS:Number = 256;
 
		public function PartialTextDataGridItemRenderer()
		{
			super();
		}
 
		public override function validateProperties():void
		{
			super.validateProperties();
 
			if (listData)
			{
				text = "";		
 
				//truncate the text if needed and render text as HTML
				htmlText = truncateLabel(listData.label);
 
				//apply style to text so Read More link looks like a link
				styleSheet = getLinkStyle();
			}
		}
 
		private static function getLinkStyle() : StyleSheet {
			var style:StyleSheet = new StyleSheet();
 
			var styleObj:Object = new Object();
			styleObj.fontWeight = "normal";
			styleObj.fontSize = "12px";
			styleObj.color = "#0000ff";
			styleObj.textDecoration = "underline";
			style.setStyle("a", styleObj);
 
			return style;
		}
 
		private static function truncateLabel(label:String) : String {
			if(label.length > MAXIMUM_NUMBER_OF_CHARACTERS) {
				label = label.substr(0,MAXIMUM_NUMBER_OF_CHARACTERS);
 
				//remove any extra whitespace at the end of the string
				label = StringUtil.trim(label);
 
				//ensure that label ends with ...
				if(label.charAt(label.length-1) == ".") {
					label = label + "..";
				}
				else {
					label = label + "...";
				}
 
				//add read more link to indicate to user that there is more
				//text and that it is clickable.
				label = label + "  <a href=\"#\">Read More</a>";
			}
 
			return label;
		}
	}
}

Next, for the itemEditor itemRenderer we use a TextArea that is set to not be editable. We also strip away the styling that would make it look like a TextArea embeded within the column.

package
{	
	import mx.controls.TextArea;
 
	/**
	 * Creates an non-editable TextArea to be used as renderer and
	 * styled so that it is seamless with the other DataGrid cells.
	 */
	public class FullTextDataGridItemRenderer extends TextArea
	{
		public function FullTextDataGridItemRenderer()
		{
			super();
			this.editable = false;
			this.setStyle("paddingLeft",5);
			this.setStyle("paddingRight",5);
			this.setStyle("paddingTop",2);
			this.setStyle("paddingBottom",2);
			this.setStyle("backgroundAlpha",0);
			this.setStyle("borderStyle", "none");
		}
	}
}

What this does is, whenever the column is clicked on, any strings that exceed the maximum length will be converted to their full length and embedded within a scrollable TextArea. It provides a seamless experience for users, by not forcing them to read a tooltip or some other dialog. Here is an example application that puts the two itemRenderers to use.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
				layout="vertical"
				width="800"
				height="600"
				paddingBottom="0" 
				paddingLeft="0" 
				paddingRight="0" 
				paddingTop="0"
				creationComplete="creationCompleteHandler(event)">
 
	<mx:Script>
		<![CDATA[
			import mx.collections.ArrayCollection;
			import mx.events.FlexEvent;
 
			[Bindable] private var gridDataProvider:ArrayCollection;
 
			/**
			 * On creationComplete, create the data provider for the DataGrid.
			 */
			protected function creationCompleteHandler(event:FlexEvent):void
			{
				gridDataProvider = new ArrayCollection();
 
				var longDescription:String = "Lorem ipsum dolor sit amet, consectetur " +
					"adipiscing elit. Maecenas pellentesque odio eget tortor feugiat " +
					"sit amet auctor neque eleifend. Curabitur pharetra nunc eget " +
					"purus hendrerit sodales. Pellentesque congue commodo felis, sed " +
					"volutpat sem vulputate sit amet. Nulla a dolor consectetur urna " +
					"laoreet rhoncus nec ut lacus. Phasellus neque felis, sagittis sed " +
					"lobortis sed, accumsan suscipit lectus. In nec placerat nulla. Proin " +
					"id sem vitae massa adipiscing luctus. Quisque vitae urna erat, a " +
					"ultrices est. Nulla scelerisque varius turpis et porttitor. Nullam " +
					"convallis elementum condimentum. Nulla ac ornare est. Phasellus " +
					"posuere vestibulum dolor nec cursus. ";
 
				var longShortDescription:String = "Lorem ipsum dolor sit amet";
 
				gridDataProvider.addItem({id:1, description:longDescription, shortDescription:longShortDescription});
 
				gridDataProvider.addItem({id:2, description:longShortDescription, shortDescription:longShortDescription});
			}
 
		]]>
	</mx:Script>
 
	<mx:DataGrid width="100%" 
				 height="100%"
				 dataProvider="{gridDataProvider}"
				 variableRowHeight="true" 
				 wordWrap="true"
				 verticalAlign="top" 
				 editable="true"
				 sortableColumns="false">
 
		<mx:columns>			
			<mx:DataGridColumn width="100"
							   dataField="id"
							   headerText="Id"
							   editable="false" />
 
			<mx:DataGridColumn dataField="description" 
							   headerText="Description"
							   editable="true"
							   itemRenderer="PartialTextDataGridItemRenderer"
							   itemEditor="FullTextDataGridItemRenderer" />
 
			<mx:DataGridColumn width="200"
							   dataField="shortDescription" 
							   headerText="Short Description"
							   editable="false" />
		</mx:columns>
	</mx:DataGrid>
</mx:Application>

The source code can be downloaded at https://github.com/joshgarnett/JoshAtAdobeSourceCode/tree/master/LargeStringsInDataGrid.