Table of contents

There are several column classes and they all have some common behaviour and properties.

# Api

# Parameters

Let's add a simple text column like we've done before:

$grid->addColumnText('name', 'Name');
1

Parameters that the method takes are: $key, $title, $column = $key. By default, the column name is the same as the key. There is a key, because you can show more data grid columns that will display only one database table column:

$grid->addColumnText('name', 'Name'); // Equivalent to $grid->addColumnText('name', 'Name', 'name');
$grid->addColumnText('name2', 'Name', 'name');
$grid->addColumnText('name3', 'Name', 'name');
1
2
3

# Templates

Columns may have it's own template. I will add one more parameter (optional) to the method ::setTemplate(), just for fun:

$grid->addColumnText('name', 'Name')
	->setTemplate(__DIR__ . '/templates/name.latte', ['foo' => 'bar']);
1
2

In that template (name.latte), we will have two variables available: $item and $foo. The parameter (expanded array) is there just in case you need it sometime.

# Renderers

We can also modify data outputting via renderer callbacks:

$grid->addColumnText('name', 'Name')
	->setRenderer(function($item) {
		return strtoupper($item->id . ': ' . $item->name);
	});
1
2
3
4

But hey, what if I want to replace just some rows? No problem, the second optional argument tells me (callback again) whether the datagrid should use your renderer or not. Example:

$grid->addColumnText('name', 'Name')
	->setRenderer(function($item) {
		return strtoupper($item->id . ': ' . $item->name);
	}, function($item) {
		return (bool) ($item->id % 2);
	});
1
2
3
4
5
6

# Replacement

Outputted data could have a simple array replacement instead of renderer callback:

$grid->addColumnText('name', 'Name')
	->setReplacement([
		'John' => 'Doe',
		'Hell' => 'o'
	]);
1
2
3
4
5

# Escaping values

By default, latte escapes all values from data source. You can disable that:

$grid->addColumnText('link_html', 'Link')
	->setTemplateEscaping(FALSE);
1
2

# Sorting

You can set the column as sortable.

$grid->addColumnText('name', 'Name')
	->setSortable();
1
2

When using doctrine as data source, you can output data the object way using dot-notation and property accessor. But when you are using column of related table for sorting, you probably want to use alias for sorting:

$grid->addColumnText('role', 'User role', 'role.name')
	->setSortable('r.name')
1
2

# Resetting pagination after sorting

$grid->addColumnText('name', 'Name')
	->setSortable()
	->setSortableResetPagination();
1
2
3

# Default sort

Datagrid implements default sorting mechanism:

$grid->setDefaultSort(['name' => 'DESC']);
1

# Resetting default sort

By default, once you reset the filter, default sort is applied. If you don't want to apply it after resetting the filter, pass FALSE as a second parameter to Datagrid::setDefaultSort():

$grid->setDefaultSort(['id' => 'DESC'], FALSE);
1

# Multiple columns sort

Sorting by multiple columns is disabled by default. But can be enabled:

$grid->setMultiSortEnabled($enabled = TRUE); // Pass FALSE to disable
1

# Default per page

You can also set default "items per page" value:

$grid->setDefaultPerPage(20);
1

# Custom sorting Callback

You can define your own sorting callback:

$grid->addColumnText('name', 'Name')
	->setSortable()
	->setSortableCallback(function($datasource, $sort) {
		/**
		 * Apply your sorting...
		 * 	(e.g. $sort = ['name' => 'ASC'])
		 */
	});
1
2
3
4
5
6
7
8

# Align

Column can be aligned to one side:

$grid->addColumnText('name', 'Name')
	->setAlign('center');
1
2

# Removing column

You can remove column from grid like so:

$grid->addColumnText('foo', 'Name', 'name');
$grid->removeColumn('foo');
1
2

# Column Text

We have discussed this in examples above - it's pretty basic column.

# Column Number

What more can ColumnNumber offer? Number formatting:

/**
 * Default format: decimals = 0, dec_point = '.', thousands_sep = ' '
 */
$grid->addColumnNumber('price', 'Price');
$grid->addColumnNumber('price2', 'Price', 'price')
	->setFormat(2, ',', '.');
1
2
3
4
5
6

# Column DateTime

DateTime formatting (or just date or just time):

/**
 * Default format: 'j. n. Y'
 */
$grid->addColumnDateTime('created', 'Date registered')
	->setFormat('H:i:s');
1
2
3
4
5

We can use column link to output a> element:

/**
 * Parameters order: $key, $name, $href = NULL, $column = NULL, array $params = NULL
 */
$grid->addColumnLink('name', 'Name', 'edit');
1
2
3
4

Now, ColumnLink is pretty clever! It passes an id parameter to the "edit" destination. Well, not id, more likely $primary_key, which can be changed. But that is not all. What if we want to pass some other parameters to the action method (or handler - edit!)? Use the last method parameter:

$grid->addColumnLink('name', 'Name', 'edit', 'name', ['role']);
1

That is still not all. You can pass the parameters under different name:

$grid->addColumnLink('name', 'Name', 'edit', 'name', ['id', 'surname' => 'name']);
1

Now, suppose the row in database with name = John and id = 5. Then the link will look something like that: /edit?id=5&surname=John!

# Open in new tab

You can tell ColumnLink to open its link in new tab:

$grid->addColumnLink('name', 'Name', 'edit')
	->setOpenInNewTab();
1
2

# Column Status

Status 1 Status 1

Once your item keep some "status" flag, it is appropriate to show user the status in highlighted form. Also, there could be a dropdown with available statuses:

$grid->addColumnStatus('status', 'Status')
	->addOption(1, 'Online')
		->endOption()
	->addOption(0, 'Offline')
		->endOption()
	->onChange[] = function($id, $new_value) { dump($id, $new_value); die; };
1
2
3
4
5
6

ColumnStatus has optional caret, icon, class and confirmation. By default, there is a caret visible and the main button that toggles statuses dropdown has class "btn-success". You can change all these properties:

$grid->addColumnStatus('status', 'Status')
	->setCaret(FALSE)
	->addOption(1, 'Online')
		->setIcon('check')
		->setClass('btn-success')
		->setConfirmation(new StringConfirmation('Do you really want set status as Online?'))
		->endOption()
	->addOption(2, 'Standby')
		->setIcon('user')
		->setClass('btn-primary')
		->endOption()
	->addOption(0, 'Offline')
		->setIcon('close')
		->setClass('btn-danger')
		->endOption()
	->onChange[] = [$this, 'statusChange'];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

There are 2 default class properties in Option. $class = 'btn-success' and $classSecondary = 'ajax btn btn-default btn-xs'. As you can see, the default request is called via ajax. You can of course change that ($option->setClassSecondary('btn btn-default')).

When ajax request changeStatus! is called, you probably want to redraw the item after changing item status:

public function createComponentColumnsGrid($name)
{
	$grid->addColumnStatus('status', 'Status')
		# ...
		->onChange[] = [$this, 'statusChange'];
}


public function statusChange($id, $new_status)
{
	# ...

	if ($this->isAjax()) {
		$this['columnsGrid']->redrawItem($id);
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

Also, option classes in dropdown can be altered:

$grid->addColumnStatus('status', 'Status')
	->addOption(1, 'Online')
	->setClassInDropdown('foo');
1
2
3

Options could be also set at once:

$grid->addColumnStatus('status', 'Status')
	->setOptions([1 => 'Online', 2 => 'Standby'])
1
2

Accessing particular option:

$grid->getColumn('status')->getOption(2)
	->setClass('btn-primary'); // For example
1
2

# Hideable columns

Columns Hiding

In example datagrid above, you can hide columns and then reveal them again. This feature is disabled by default. You can enable it like this:

$grid->setColumnsHideable();
1

Hidden columns are saved into session, so they will remain hidden along all next requests.

# Default hide

Columns can be hidden by default:

$grid->addColumnText('name', 'Name')
	->setDefaultHide(); // Or disable default hide: ::setDefaultHide(FALSE)
1
2

If default hide is used, new button is shown in that settings (gear) dropdown - Show default columns:

# Columns Summary

Datagrid implements a feature that allows you to display sum of column of displayed items at the bottom of the grid. Try it out:

$grid->addColumnNumber('in', 'Income')
	->setFormat(2, ',', '.');

$grid->addColumnNumber('out', 'Expenses')
	->setFormat(2, ',', '.');

$grid->setColumnsSummary(['in', 'out']);
1
2
3
4
5
6
7

Summary will be aligned to the same site as the column it is counting. By default, number format is taken also from it's column, but you can change the formatting (for each sum separately):

$grid->setColumnsSummary(['in', 'out'])
	->setFormat('out', 0, '.', ' ');
1
2

Sure you can use your own callback for each row item number to be add to summary:

$grid->setColumnsSummary(['id'], function($item, $column) {
	return $item->{$column} * 10;
});
1
2
3

And as many other places, you may want to use your own renderer callback to show user altered summary data:

$grid->setColumnsSummary(['price', 'amount'])
	->setRenderer(function($sum, string $column): string {
		if ($column === 'price') {
			return $sum . ' $';
		}

		return $sum . ' items';
	});
1
2
3
4
5
6
7
8

# Aggregation Function

# Single column

Some column aggregation can be viewed either using columns summary or using Aggregation Function:

$grid->addAggregationFunction('status', new FunctionSum('id'));
1

This will render a sum of ids under the "status" column.

As mentioned above, there is one aggregation function prepared: Contributte\Datagrid\AggregationFunction\FunctionSum. You can implement whatever function you like, it just have to implement Contributte\Datagrid\AggregationFunction\ISingleColumnAggregationFunction.

# Multiple columns

In case you want to make the aggregation directly using SQL by your domain, you will probably use interface IMultipleAggregationFunction (instead of ISingleColumnAggregationFunction):

$grid->setMultipleAggregationFunction(
	new class implements IMultipleAggregationFunction
	{

		/**
		 * @var int
		 */
		private $idsSum = 0;

		/**
		 * @var float
		 */
		private $avgAge = 0.0;


		public function getFilterDataType(): string
		{
			return IAggregationFunction::DATA_TYPE_PAGINATED;
		}


		public function processDataSource($dataSource): void
		{
			$this->idsSum = (int) $dataSource->getConnection()
				->select('SUM([id])')
				->from($dataSource, '_')
				->fetchSingle();

			$this->avgAge = round((float) $dataSource->getConnection()
				->select('AVG(YEAR([birth_date]))')
				->from($dataSource, '_')
				->fetchSingle());
		}


		public function renderResult(string $key)
		{
			if ($key === 'id') {
				return 'Ids sum: ' . $this->idsSum;
			} elseif ($key === 'age') {
				return 'Avg Age: ' . (int) (date('Y') - $this->avgAge);
			}
		}
	}
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

This aggregating is used along with Dibi in the demo.

# Column (th>, td>) attributes

Since table cell elements are rendered using Nette\Utils\Html, you can easily alter their html attributes (class, data-attributes etc):

$th = $grid->addColumnText('name', 'Name')
    ->getElementPrototype('td'); // Or element <th> via Column::getElementPrototype('th')

$th->data('foo', 'bar');
$th->class('super-column')
1
2
3
4
5

If you want to modify attributes for both th> and td> at one time, use directly Column::addCellAttributes():

$grid->addColumnText('name', 'Name')
    ->addCellAttributes(['class' => 'text-center']);
1
2

# Column callback

When you need to modify columns just before rendering (maybe remove some status options or completely change renderer for particular items), you can create column callback, that will be called with $column and $item in parameter:

$grid->addColumnLink('link', 'Link', 'this#demo', 'name', ['id', 'surname' => 'name']);

$grid->addColumnStatus('status', 'Status')
	->addOption(1, 'Online')
		->setClass('btn-success')
		->endOption()
	->addOption(2, 'Standby')
		->setClass('btn-primary')
		->endOption()
	->addOption(0, 'Offline')
		->setClass('btn-danger')
		->endOption()
	->onChange[] = [$this, 'changeStatus'];

$grid->addColumnCallback('status', function($column, $item) {
	if ($item->id == 2) {
		$column->removeOption(2);
	}
});

$grid->addColumnCallback('link', function($column, $item) {
	if ($item->id == 2) {
		$column->setRenderer(function() {
			return '';
		});
	}
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

That is the code of the demo shown above. As you can see, item with id == 1 does have an empty link column and only 2 options in ColumnStatus.

$grid->addColumnCallback('status', function($column, $item) {
	if ($item->id == 2) {
		$column->setTemplate(NULL);
		$column->setRenderer(function() {
			return 'My super another status';
		});
	}
});
1
2
3
4
5
6
7
8