Legacy Documentation
You are using the documentation for version 3.5.17. Go here for the latest version or check here for your available upgrades to the latest version.
CP/Table Service¶
Overview¶
Tables are the most common way to view and navigate data in the ExpressionEngine control panel. Since tables share a lot of common functionality, we’ve abstracted most of it out to a Table service to handle tasks such as displaying the table markup, and sorting and filtering tabular content. The Table service should handle most idioms covered in the style-guide for tables.
Below, we’ll cover the steps needed to create a table from inside a controller.
Creating a new table¶
The first thing we need to do is create our table object. This can be done by reaching into the dependency injection container and optionally passing along a few options that can affect the behavior and appearance of the table:
// Use default options
$table = ee('CP/Table');
// Specify other options
$table = ee('CP/Table', array('autosort' => TRUE, 'autosearch' => TRUE));
Here are the available options:
Option name | Description | Accepted values | Default value |
---|---|---|---|
autosearch | Assuming the entire dataset is given to setData() ,
the Table service can automatically handle searching
of the table’s data. The Table service will
automatically get a search term from the search
key in POST or GET , or a search term can be
specified via the search configuration option
outlined below. If you have a large data set, it’s
recommended to disable autosearch and perform the
search via SQL or other means before handing the data
off to the table. |
TRUE or FALSE
to enable or disable,
respectively. |
FALSE |
autosort | Assuming the entire dataset is given to setData() ,
the Table service can automatically handle sorting
of the table’s data via column. The Table service will
automatically look for a sort column and direction in
GET , or they can be set manually via the
sort_col and sort_dir configuration options
outlined below. If you have a large data set, it’s
recommended to disable autosort and perform the
sort via SQL or other means before handing the data
off to the table. |
TRUE or FALSE
to enable or disable,
respectively. |
FALSE |
class | An optional CSS class to add to the table tag | String | NULL |
lang_cols | Whether or not to run passed column names through the
lang() helper on the front-end. |
TRUE or FALSE
to enable or disable,
respectively. |
TRUE |
limit | Number of table rows to limit the data display by for the purposes of pagination. | A natural number greater than zero. | 20 |
grid_input | Whether or not this table is to behave as Grid-like input interface. | TRUE or FALSE
to enable or disable,
respectively. |
FALSE |
page | When autosort and optionally autosearch are
set to TRUE , specifies the page number to show in
a set of paginated data. If page is found in the
page’s query string, its value will be used. |
A natural number greater than zero. | 1 |
reorder | Whether or not to show a reorder handle on the left
side of the table for reordering table rows. This can
be used in conjunction with the eeTableReorder
jQuery plugin documented below. |
TRUE or FALSE
to enable or disable,
respectively. |
FALSE |
search | When autosearch is set to TRUE , specifies the
search term used to search table contents.
be used in conjunction with the eeTableReorder
jQuery plugin documented below. |
String or integer | NULL |
sort_col | Specifies the column the table is currently being
sorted by, identified by the column identifier,
described below. If sort_col is found in the
page’s query string, its value will be used. When
autosort is enabled, the Table library will
perform the sort. The sort_col value also
determines which column is visually highlighted on the
table interface. |
String | NULL |
sort_col_qs_var | Specifies the query string variable used to specify the column to sort the table by. This is typically only used if more than one table is displayed on a page. | String | sort_col |
sort_dir | Specifies the direction of the table sort.
sorted by, identified by the column identifier,
described below. If sort_dir is found in the
page’s query string, its value will be used. When
autosort is enabled, the Table library will
perform the sort. The sort_dir value also sets the
visual indicator for sort direction on the table
interface. |
asc or desc |
asc |
sort_dir_qs_var | Specifies the query string variable used to specify the direction of the table sort. This is typically only used if more than one table is displayed on a page. | String | sort_dir |
sortable | Whether or not the table should allow sorting via
user interaction. When set to FALSE , column
headings will not be click-able, highlighted, or show
the visual sort direction indicators. |
TRUE or FALSE
to enable or disable,
respectively. |
TRUE |
Setting the columns¶
Now that our Table object is set up, let’s start describing our data. First, we’ll set up the headings for each column. Let’s say we want to show a list of Channels, we’ll then pass in an array of language keys that represent the relevant columns:
$table->setColumns(
array(
'id',
'channel',
'short_name',
'manage' => array(
'type' => Table::COL_TOOLBAR
),
array(
'type' => Table::COL_CHECKBOX
)
)
);
Note
Be sure to include the Table class’s namespace at the top of
your file to use its constants:
use EllisLab\ExpressionEngine\Library\CP\Table;
Notice we specified some extra parameters for two of the columns. The
“Manage” column is going to be of type COL_TOOLBAR
which can have
various action buttons related to the individual Channel. And our last
column is just for checkboxes, so that a user can select Channels to
perform actions on them in bulk.
While we’re here, let’s set the “no results” text. This is the message that appears in the table when there are no items to display, and also provides a call-to-action to add items to the table:
$table->setNoResultsText('no_channels', 'create_channel', ee('CP/URL', 'channels/create'));
The first parameter is the language key that lets the user know there are no Channels to display. The second parameter is the text for the call-to-action button, and the third parameter is the URL for the button.
We should be at a point where we can see how our table is coming along. To show the table in a view, we’ll ask the Table object to compile data to be consumed by a view, and then pass that data to our view:
// Pass in a base URL to create sorting links
$vars['table'] = $table->viewData(ee('CP/URL', 'channels'));
return ee('View')->make('channels/index')->render($vars);
In our view, we’ll take the data and render the table markup by loading a shared view:
<?php $this->embed('ee:_shared/table', $table); ?>
Given what we’ve done so far, our table looks like this:
Table columns can have the following options set on them:
Option name | Description | Accepted values | Default value |
---|---|---|---|
label | If you’d rather not specify the label has the options array’s key as done above, you can specify it here. This would also allow columns to have the same label, if needed. | String | NULL |
encode | Whether or not to encode and escape the content of the
cell to prevent markup or other code from executing on
display. It’s typically best practice when dynamic,
user-generated content is displayed, to escape its
output. But if a table cell needs to contain and
render HTML, encode should be set to FALSE for
those columns. |
TRUE or FALSE to
enable or disable,
respectively. |
TRUE |
sort | Whether or not to allow the column data to be sorted. By default, all text-based columns can be sorted, but other columns, such as toolbars and checkboxes, are not sortable. | TRUE or FALSE to
enable or disable,
respectively. |
TRUE for COL_TEXT
and COL_STATUS columns.
FALSE for
COL_CHECKBOX and
COL_TOOLBAR columns. |
type | Specifies the type of column, which ultimately determines how data will be interpreted and displayed in the view. | Table::COL_TEXT
Table::COL_TOOLBAR
Table::COL_CHECKBOX
Table::COL_STATUS |
Table::COL_TEXT |
Setting the data¶
For the purposes of this guide, we’ll get all the Channels for the current site:
$channels = ee('Model')->get('Channel')
->filter('site_id', ee()->config->item('site_id'))
->all();
Next, we’ll construct an array with the Channel data we want to display:
$data = array();
foreach ($channels as $channel)
{
$edit_url = ee('CP/URL', 'channels/edit/'.$channel->getId());
$data[] = array(
$channel->getId(),
array(
'content' => $channel->channel_title,
'href' => $edit_url
),
$channel->channel_name,
array('toolbar_items' => array(
'edit' => array(
'href' => $edit_url,
'title' => lang('edit')
),
'settings' => array(
'href' => ee('CP/URL', 'channels/settings/'.$channel->getId()),
'title' => lang('settings')
)
)),
array(
'name' => 'channels[]',
'value' => $channel->getId(),
'data' => array(
'confirm' => lang('channel') . ': <b>' . htmlentities($channel->channel_title, ENT_QUOTES) . '</b>'
)
)
);
}
Notice the data is in the same order we set the columns. For the toolbar column, we pass a specifically-formatted array that tells the Table service what kind of button to show, as well as the link but the button and its title text. For the checkbox column, we need to specify the input name for the checkboxes, its value, as well as any optional data like the data we set here to work with an action modal.
Passing an array with the keys content
and href
will wrap the contents
in an <a>
tag, but only if the column has encode
set to TRUE
.
Note
Only use an edit URL when sending an href
key along with the
contents of a column.
Finally, we’ll tell our Table object about our data:
$table->setData($data);
Our table should now be filled with the available data and look the way we’ve configured:
Reorder-able rows¶
Tables built with the Table service support reordering of its rows and provides a JavaScript callback to perform any actions necessary post-reorder, such as any AJAX calls.
To create a table with reorder-able rows, we’ll create a new Table object with some specific options set:
$table = ee('CP/Table', array(
'reorder' => TRUE,
'sortable' => FALSE
));
From there, we’ll set our columns and data as usual. But to get it all working, we’ll need to include some JavaScript assets to facilitate the reorder:
ee()->cp->add_js_script('file', 'cp/sort_helper');
ee()->cp->add_js_script('plugin', 'ee_table_reorder');
Notice we loaded ExpressionEngine’s table reordering plugin. We’ll need to write some custom JavaScript to bind the plugin to our table, as well as perform any callback actions we may need:
$('table').eeTableReorder({
afterSort: function(row) {
// Whatever you like
}
});
Notice there is a row object passed to the callback so that you can access the row that was moved, or any of its parents, siblings or children.
If we load our view, we should now see our table has reorder handles on the left side and we can drag them up and down the page to reorder the rows:
Using as a Grid input¶
The Table service is extend-able, and we’ve extended it to create a special GridInput service that can be used to create the very same user interface as our Grid field. Working with it is very similar to building a regular table.
First, we’ll create a new GridInput object and specify the base input
name that all inputs will be namespaced under. This is the name you’ll
access the Grid’s data from POST
with:
$grid = ee('CP/GridInput', array(
'field_name' => 'image_manipulations'
));
Next, we’ll set our columns as usual, but GridInput offers one more option to columns, and it’s the option to set instructions or a description for the column. So we’ll specify the column titles and their corresponding descriptions with language keys:
$grid->setColumns(
array(
'image_manip_name' => array(
'desc' => 'image_manip_name_desc'
),
'image_manip_type' => array(
'desc' => 'image_manip_type_desc'
),
'image_manip_width' => array(
'desc' => 'image_manip_width_desc'
),
'image_manip_height' => array(
'desc' => 'image_manip_height_desc'
)
)
);
While we’re here, we’ll go ahead and set our “no results” message and button label. The function only takes two parameters here as a URL is not needed:
$grid->setNoResultsText('no_manipulations', 'add_manipulation');
Now, assuming we’ve already gathered the data we need in our $sizes
variable, we’ll set our data:
$data = array();
foreach ($sizes as $size)
{
$data[] = array(
'attrs' => array('row_id' => $size['id']),
'columns' => array(
form_input('short_name', $size['short_name']),
form_dropdown(
'resize_type',
array(
'constrain' => lang('image_manip_type_opt_constrain'),
'crop' => lang('image_manip_type_opt_crop'),
),
$size['resize_type']
),
form_input('width', $size['width']),
form_input('height', $size['height'])
)
);
}
$grid->setData($data);
Notice the row is a bit more multidimensional this time. The data row
now has an attrs
key to set attributes on the table row element,
and the actual row data has moved to the columns
key. This can be
done on any Table object for specifying row attributes. But we’re
setting a content ID attribute here so that GridInput can properly
namespace the inputs. And since this table is for inputting data, we
enter inputs directly in to the data array this time, and populate them
with our existing data, if available.
Which may beg the question, where do new rows come from? We’ve only
entered existing rows so far, but GridInput needs a template to base new
rows off of. We’ll call setBlankRow()
to tell GridInput what a blank
row should look like:
$grid->setBlankRow(array(
form_input('short_name'),
form_dropdown(
'resize_type',
array(
'constrain' => lang('image_manip_type_opt_constrain'),
'crop' => lang('image_manip_type_opt_crop'),
)
),
form_input('width'),
form_input('height')
));
Before we hand the Grid off to the view, we need to load all of its JavaScript assets and initialization:
$grid->loadAssets();
Finally, just as we do with regular tables, we call viewData()
and
pass the data to our view where we render it with the
ee:_shared/table
view in our add-on view:
$vars['grid'] = $grid->viewData();
return ee()->cp->render('myaddon/myview', $vars);
Here is the final, fully functional output of our code:
If you’re using the Shared Form View, your fieldset definition should look something like this:
array(
'title' => 'constrain_or_crop',
'desc' => 'constrain_or_crop_desc',
'wide' => TRUE,
'grid' => TRUE,
'fields' => array(
'image_manipulations' => array(
'type' => 'html',
'content' => ee()->cp->render('ee:_shared/table', $grid->viewData(), TRUE)
)
)
)
Note we’re setting wide
to denote the field should take up the entire width
of the form, and grid
so the form display logic can do the necessary markup
tweaks for proper styling and behavior of the Grid.
For those not using the Shared Form View, make sure your Grid is in a div tag
instead of a fieldset tag and make sure it has a class of grid-publish
.