There are several steps required so that sorting works properly. The state variables list.ordering and list.direction are used to store the ordering column and ordering direction (ascending or descending).

Step 1: Model File

In the model file, which generates the data that will form the table, in the function getListQuery(), before returning the query, you need to get these two state variables and then you need to adjust the query so that the order parameters are taken into account.

// Add the list ordering clause.
$orderCol = $this->state->get('list.ordering', 'id');
$orderDirn = $this->state->get('list.direction', 'DESC');

$query->order($db->escape($orderCol) . ' ' . $db->escape($orderDirn));

Step 2: View File

After generating the sorting variables in the model, you need to set the initial state in the view file.

// Get application
$app = JFactory::getApplication();
$context = "forum.list.admin.contacts";

$this->state = $this->get('State');

// Initial state for sorting and ordering
$this->filter_order = $app->getUserStateFromRequest($context.'filter_order', 'filter_order', 'id', 'cmd');
$this->filter_order_Dir = $app->getUserStateFromRequest($context.'filter_order_Dir', 'filter_order_Dir', 'desc', 'cmd');

Step 3: Template File

Then, you can assign these variables in your template file.

$listOrder = $this->escape($this->filter_order);
$listDirn = $this->escape($this->filter_order_Dir);

Step 4: Hidden Fields - Template File

You also need to add a couple of hidden fields to the form in the template file. They are generally placed just before the closing the form tag, like this:

<form id="adminForm" method="post" name="adminForm">

.... table goes here ....

<input type="hidden" name="filter_order" value="<?php echo $listOrder; ?>" />
<input type="hidden" name="filter_order_Dir" value="<?php echo $listDirn; ?>" />

These are used to send ordering column and direction back to the server.

Step 5: Column Headers - Template File

You need to replace the static column names with grid.sort Jhtml static class. First argument must be 'grid.sort'. Second argument is the name of the column that visitors actually see. Third argument is the name of the corresponding database field (column) that is to be sorted on. This is passed to the model. Fourth and fifth arguments are the current order direction (ascending or descending) and the name of the column that the table is currently sorted on.

For example,

<th width="2%">
 <?php echo JHtml::_('grid.sort', 'JGRID_HEADING_ID', 'id', $listDirn, $listOrder); ?>

Step 6: Allowable Columns - Model File

You need add the names of all columns by which your data can be sorted to the 'filter_fields' config, like this:

public function __construct($config = array())
// Allowable Columns
$config['filter_fields'] = array(
// ...

If you use column prefixes in your query, you can also specify them along with the column name (like '').