Defining Grid Structures

In the Hello dgrid tutorial, we explored the basic single-row column structures that dgrid has to offer, and in this tutorial we aim to demonstrate further options for arranging columns.

For the examples in this tutorial, we will be creating a grid with various column structures containing information on hall of fame batters. We will start off with a simple baseline grid containing just the batters' first and last names. We'll store our batter information in a JSON file and use the dstore/RequestMemory module to pull it in.

	<div id="grid" class="grid"></div>
	require([
		'dstore/RequestMemory',
		'dgrid/OnDemandGrid'
	], function (RequestMemory, OnDemandGrid) {

		var grid = new OnDemandGrid({
			collection: new RequestMemory({ target: 'hof-batting.json' }),
			columns: [
				{ field: 'first', label: 'First' },
				{ field: 'last', label: 'Last' }
			]
		}, 'grid');

		grid.startup();
	});
View Demo

Remember to call startup since we are creating this grid programmatically.

Parts of the Grid

The structure of a grid is comprised of multiple parts. Let's look at these parts in detail.

Header

The header contains cells which display the label of each column. It can be disabled by setting showHeader: false in the arguments object passed to the Grid constructor; it can also be displayed or hidden later using set("showHeader", ...)

Content

This is the region where rows are rendered for each data item.

Column Set

The dgrid/ColumnSet mixin provides functionality which divides a grid's column structure into multiple distinct sets, each of which manages its columns' horizontal scrolling independently. This makes it possible to keep certain columns in view even while others are scrolled out of viewing range.

Usage of column sets is completely opt-in; this will be further explained later in this tutorial.

Row

The content section contains multiple rows of data. Each row represents a single data item.

Sub-row

Sub-rows allow for breaking up the representation of each item across multiple rows, which can aid in readability when there are many fields to display. Since each item's full representation is already commonly referred to as a "row", we refer to each of these rows within each item as "sub-rows" to distinguish between the two concepts.

Cell

The smallest element of the grid, each cell typically represents one field of a single data item.

Defining Sub-rows

Sub-rows can be useful when there are many fields to display. To define a sub-row, we pass an array of arrays via the subRows property of the arguments object. Each inner array defines the columns for a single sub-row, in order; thus, in the following example, the first inner array defines the top sub-row and the second array defines the bottom sub-row:

	require([
		'dstore/RequestMemory',
		'dgrid/OnDemandGrid'
	], function (RequestMemory, OnDemandGrid) {
		var grid = new OnDemandGrid({
			collection: new RequestMemory({ target: 'hof-batting.json' }),
			subRows: [
				[
					{ field: 'first', label: 'First', rowSpan: 2 },
					{ field: 'last', label: 'Last', rowSpan: 2 },
					{ field: 'bats', label: 'Bats', rowSpan: 2 },
					{ field: 'throws', label: 'Throws', rowSpan: 2 },
					{ field: 'totalG', label: 'G' },
					{ field: 'totalAB', label: 'AB' },
					{ field: 'totalR', label: 'R' },
					{ field: 'totalRBI', label: 'RBI' },
					{ field: 'totalBB', label: 'BB' },
					{ field: 'totalK', label: 'K' }
				],
				[
					{ field: 'totalGAB', label: 'Games as Batter', colSpan: 2 },
					{ field: 'totalH', label: 'H' },
					{ field: 'total2B', label: '2B' },
					{ field: 'total3B', label: '3B' },
					{ field: 'totalHR', label: 'HR' }
				]
			]
		}, 'grid');

		grid.startup();
	});
View Demo

When subRows is specified, it supersedes columns. In fact, defining subRows with a single inner array is equivalent to defining columns as an array.

You may have noticed that due to the widths of the columns in this example, the entire grid horizontally scrolls. This can tend to happen when there are many fields to display. Next we'll explore an alternative solution to situations such as this one.

Defining Column Sets

Column sets allow us to define complex grid structures involving multiple independently-scrolling sets of columns, each containing one or more sub-rows. Column set functionality is provided via a separate mixin, since it is a feature that isn't necessarily used in the majority of cases.

Thus, to incorporate support for column sets into a grid, we must first use dojo/_base/declare to create a grid constructor which includes the functionality from the ColumnSet mixin. We can then use the custom constructor the same way we used OnDemandGrid, and additionally specify the columnSets property:

	require([
		'dstore/RequestMemory',
		'dgrid/OnDemandGrid',
		'dojo/_base/declare',
		'dgrid/ColumnSet'
	], function (RequestMemory, OnDemandGrid, declare, ColumnSet) {
		var CustomGrid = declare([ OnDemandGrid, ColumnSet ]);
		var grid = new CustomGrid({
			collection: new RequestMemory({ target: 'hof-batting.json' }),
			columnSets: [ /* ... */ ]
		}, 'grid');

		grid.startup();
	});

Like subRows, the columnSets property accepts a nested array; however, this array contains three levels of arrays (column sets, sub-rows, then individual columns). This can be a confusing concept, so let's see a working example of it:

	require([
		'dstore/RequestMemory',
		'dgrid/OnDemandGrid',
		'dojo/_base/declare',
		'dgrid/ColumnSet'
	], function (RequestMemory, OnDemandGrid, declare, ColumnSet) {
		var CustomGrid = declare([ OnDemandGrid, ColumnSet ]);
		var grid = new CustomGrid({
				collection: new RequestMemory({ target: 'hof-batting.json' }),
				columnSets: [
					[
						[
							{ field: 'first', label: 'First'},
							{ field: 'last', label: 'Last' }
						],
						[
							{ field: 'bats', label: 'Bats' },
							{ field: 'throws', label: 'Throws' }
						]
					], [
						[
							{ field: 'totalG', label: 'G' },
							{ field: 'totalAB', label: 'AB' },
							{ field: 'totalR', label: 'R' },
							{ field: 'totalRBI', label: 'RBI' },
							{ field: 'totalBB', label: 'BB' },
							{ field: 'totalK', label: 'K' }
						],
						[
							{ field: 'totalGAB', label: 'Games as Batter', colSpan: 2 },
							{ field: 'totalH', label: 'H' },
							{ field: 'total2B', label: '2B' },
							{ field: 'total3B', label: '3B' },
							{ field: 'totalHR', label: 'HR' }
						]
					]
				]
			}, 'grid');

			grid.startup();
		});
	});
View Demo

Each individual column set will have a horizontal scrollbar if its columns' widths exceed the width of the column set itself. This allows one column set to scroll while the others remain stationary.

To better understand the way we can style this grid to allow the second column set to scroll, let's take a look at the CSS used for the example:

	.grid {
		width: 700px;
		margin: 10px;
	}

	/* Default all cells to 80px width */
	.grid .dgrid-cell {
		width: 80px;
	}

	/* Make the columns for first/last name wider */
	.grid .field-first,
	.grid .field-last {
		width: 100px;
	}

	/*
		For the column set example, make each column set occupy
		half the total grid width.
	*/
	.grid .dgrid-column-set-cell {
		width: 50%;
	}

In this example, the total grid width is 700px. Since the combined widths of the columns in the right column set exceed the total width allotted to that column set, the content overflows and a scrollbar appears. Unlike the previous sub-row example, however, in this case only the content within the right column set scrolls.

As seen in the above example, the most common way to set the width of a specific column is by using the .field-<fieldname> CSS class.

Defining Spanned Column Headings with the CompoundColumns Extension

In addition to the standard column structures explained previously, a more recent addition to the dgrid project is the CompoundColumns extension. This extension adds the ability to define a column structure which includes additional spanning header cells above the actual columns in the grid. It is used the same way as a mixin; the only difference is it lives in the extensions subfolder since it is a less common feature:

	require([
		'dstore/RequestMemory',
		'dgrid/OnDemandGrid',
		'dojo/_base/declare',
		'dgrid/extensions/CompoundColumns'
	], function (RequestMemory, OnDemandGrid, declare, CompoundColumns) {
		var CustomGrid = declare([ OnDemandGrid, CompoundColumns ]);
		var grid = new CustomGrid({
			collection: new RequestMemory({ target: 'hof-batting.json' }),
			columns: [
				{
					label: 'Full Name',
					children: [
						{ field: 'first', label: 'First' },
						{ field: 'last', label: 'Last' }
					]
				},
				{ field: 'totalGAB', label: 'Games as Batter' }
			]
		}, 'grid');

		grid.startup();
	});
View Demo

Conclusion

dgrid offers powerful components for efficiently presenting data. Whether just displaying a few simple columns, or many fields in a complex structure, dgrid has you covered. This tutorial has provided simple examples of each of the types of structures dgrid supports. For more information, see the respective pages of the dgrid documentation.

Resources