Posts Tagged ‘hide’

Presenting Summary-Detail Content

Monday, November 3rd, 2008

I was recently working on a task with Jon Rose (Jon’s Blog). We basically needed to implement the typical summary-detail functionality.

At a high level, we needed to show a DataGrid containing a list of items, along with some summary information about each item. The user would then select the item that they wanted to work with. At that point, we would remove the summary list and display the details of the item.

Removing the summary list allowed us to save screen real estate by removing now-irrelevant information (the user no longer needed to see the items that they did not select). However, this also meant that we were no longer displaying the summary information about the item that the user did select.

Although the summary information is typically present in the detail section, it is usually preferred that it also be presented as a header or title above the details. We could have created a Label to display this header/summary information. However, we already had a DataGrid row that displayed exactly what we needed. Furthermore, at this point, the user is already accustomed to seeing the summary data in this format. We wanted to keep the flow from summary-view to detail-view as obvious as possible.

What we really wanted was to keep the summary DataGrid, but shrink it to only show a single row. That single row should only show the item that the user had selected. We tried setting the row count to 1 and scrolling to put the selected item in view. But, that led to dealing with a scrollbar and some other annoying issues.

What we decided to do, instead, turned out to be much more simple (and, in hindsight, seemingly obvious!). Instead of trying scroll a DataGrid to the proper item, we created a filter to eliminate everything except the selected item. At that point, the DataGrid would only contain one item (the selected item). Thus, we could set the DataGrid’s row count to 1, and not have any of the other issues (scrollbars, etc.). Here is an example:

This behavior allowed us to keep the selected item’s summary information available in the form that the user was used to. It avoided the creation/maintenance of another way of displaying the summary information. It also allowed us to reclaim screen real estate. And, it was simple.

The remainder of this page discusses the code behind the example. I have omitted things like widths and resizing effects in an effort to simplify the conversation. First, we create your basic DataGrid:

<mx:DataGrid id="stockDG" dataProvider="{this.stocks}" itemClick="selectStock(event)">
	<mx:columns>
		<mx:DataGridColumn headerText="Company Name" dataField="companyName" />
		<mx:DataGridColumn headerText="Symbol" dataField="symbol" />
		<mx:DataGridColumn headerText="Exchange" dataField="exchange" />
		<mx:DataGridColumn headerText="Industry" dataField="industry" />
	</mx:columns>
</mx:DataGrid>

In addition, we will create a “details” section that will initially be invisible:

<mx:VBox id="viewDetailVbox" visible="false" includeInLayout="false">
	<mx:HBox width="100%" height="100%" backgroundColor="#F2F1F1">
		<mx:Label text="Company" />
		<mx:TextInput id="companyDetail" />
		<mx:Label text="Symbol" />
		<mx:TextInput id="symbolDetail" />
	</mx:HBox>
	<!-- ... (continue adding details fields) -->
</mx:VBox>

We will also create some buttons to allow the user to either update the data with any changes they made in the details section … or to cancel any changes they may have made.

<mx:HBox id="buttonsBox" visible="false" includeInLayout="false">
	<mx:Button label="Update" click="updateSelectedStock(event)"/>
	<mx:Button label="Cancel" click="closeSelectedStock(event)"/>
</mx:HBox>

When an item in the DataGrid is clicked, the selectStock(event) function will be called. Here is that code:

private function selectStock(event:ListEvent):void {
	this.selectedStock = Stock(stockDG.selectedItem);
	stockDG.selectedItem = null;

	filterArrayCollectionToSelectedItemOnly();
	collapseDataGridToOneRow();
	displayDetailsOfSelection();
}

And, here are the functions that are called by the selectStock(event) function:

private function filterArrayCollectionToSelectedItemOnly():void {
	//assign the filter function to use
	this.stocks.filterFunction = filterStocksToSelectedItemOnly;

	//run the filter
	this.stocks.refresh();
}

private function filterStocksToSelectedItemOnly(item:Object):Boolean {
	var thisIsTheSelectedItem:Boolean = false;
	if(item == this.selectedStock) {
		thisIsTheSelectedItem = true;
	}
	return thisIsTheSelectedItem;
}

private function collapseDataGridToOneRow():void {
	stockDG.rowCount = 1;
}

private function displayDetailsOfSelection():void {
	this.companyDetail.text = this.selectedStock.companyName;
	this.symbolDetail.text = this.selectedStock.symbol;
	//... (continue setting remaining values)

	showDetailsAndButtons();
}

If the user wishes to return to the summary list (by clicking either the Update or Cancel button), we will reset the DataGrid to contain all of the items by removing the fiter, calling refresh() on the collection being used by the dataProvider, and setting the rowCount to the number of items in the list. In addition, we will remove the details section and the buttons from display.

private function closeSelectedStock(event:Event):void {
	this.selectedStock = null;
	this.stocks.filterFunction = null;
	this.stocks.refresh();
	stockDG.rowCount = this.stocks.length;

	hideDetailsAndButtons();
}

Finally, here are the two functions that hide and display the details section and the buttons:

private function showDetailsAndButtons():void {
	viewDetailVbox.visible = true;
	viewDetailVbox.includeInLayout = true;
	this.buttonsBox.visible = true;
	this.buttonsBox.includeInLayout = true;
}

private function hideDetailsAndButtons():void {
	viewDetailVbox.visible = false;
	viewDetailVbox.includeInLayout = false;
	this.buttonsBox.visible = false;
	this.buttonsBox.includeInLayout = false;
}