Showing sortable column indicators in CGridView

Hello all,

I’m really enjoy Yii, though I have to say it’s quite overwhelming sometimes to get my arms around it all.

For a CGridView, I wanted the sortable columns to indicate this without the user having to hover over the link, and the obvious way is to just add a ** token to the header text:




$this->widget('zii.widgets.grid.CGridView', array(

    'dataProvider' => new CArrayDataProvider(

        $model->search(), array(

            'sort' => array(

                ...

                'attributes' => array('column1', 'somecolumn2')

            )

        )

    ),

    'columns' => array(

        array(

            'header' => '** Column 1',                // ** tells the user it's sortable

            'value'  => '$data->column1',

            'sortable' => true,

            'name'     => 'column1',

        ),

        ...



Though I have to maintain the sortable-ness of each column anyway (with the sortable=>yes attribute), I can still mess up by mis-specifying the sort=>(…) property in the dataProvider, which means I’d have ** Column1 even though the column is not actually sortable.

In my first attempt at overriding a system-y class to make this ** appear automatically, I did these things.

First, after finding that CDataColumn::renderHeaderCellContent() created this header, I created a small class file that overrode this, either adding the token if all the stars align, or punted to the parent class (I also added "application.extensions.*" to the imports section in config/main.php).




// in extensions/MySortableDataColumn.php

class MySortableDataColumn extends CDataColumn {


        protected function renderHeaderCellContent()

        {

                $token = "** ";


                if ($this->grid->enableSorting && $this->sortable && $this->name !== null)

                        echo $this->grid->dataProvider->getSort()->link($this->name, $token . $this->header);

                else

                        parent::renderHeaderCellContent();

        }


        protected function getSortable()

        {

                return true;

        }

}



I also define getSortable() to avoid having to define sortable=>true in each column.

Then, I set the class=> attribute in each sortable column, which causes the framework to load my class instead of the base class, so it automatically sets sortable=>true and tags the header with ** if it’s ultimately sortable. This does not appear to interfere with the actual sorting mechanism.




$this->widget('zii.widgets.grid.CGridView', array(

    'dataProvider' => new CArrayDataProvider(

        $model->search(), array(

            'sort' => array(

                ...

                'attributes' => array('column1', 'somecolumn2')

            )

        )

    ),

    'columns' => array(

        array(

            'header' => 'Column 1',

            'value'  => '$data->column1',


            'class'    => 'MySortableDataColumn',                // NEW

            'name'     => 'column1'

        ),

        ...



So far it works, but I don’t know if it’s kosher or silly or optimal or what.

Any thoughts?

Why don’t you just display the sortable columns in a different colour, or underline the headings? I.e. just use CSS to style the hyperlink.

Whether I use color or underlines or ** text, I want the styling to be applied automatically only if I have done all the right things to make a column actually sortable.

When I was first mucking with this, I had mismatches all the time between the visual appearance of a this-is-sortable column with whether it was actually sortable, and I hate getting things like that wrong. By teaching the system how to apply that styling - whatever it is - automatically only when everything is right, it’s easier to test and less prone to errors.

Or am I missing a better way to accomplish this?

Replying to my own post, I did decide to augment this mechanism with CSS, though it still requires the class override to make it so. I’ll document it here in case somebody else wants to solve this problem:




// in extensions/MySortableDataColumn.php

class MySortableDataColumn extends CDataColumn {


        protected function renderHeaderCellContent()

        {

                if ($this->grid->enableSorting && $this->sortable && $this->name !== null)

                        echo $this->grid->dataProvider->getSort()->link(

                            $this->name,

                            $this->header,

                            array( 'class' => 'sortable' )

                        );

                else

                        parent::renderHeaderCellContent();

        }


        protected function getSortable()

        {

                return true;

        }

}



and then in css/main.css the styling is to just underline the header text, but of course you could do blink if you want :slight_smile:




.grid-view table.items th A.sortable

{

        text-decoration: underline;

}



This is working really well so far.