How to customize your grid columns visible and order by user themselves

  1. Goal
  2. Sample Picture
  3. Add code in controller
  4. Add code in model
  5. Adjust your view code
  6. a.Register JS
  7. b.Show Config Columns link
  8. c.Add partial render code in your view file
  9. d.That partial render real file
  10. Some Help Functions

Goal

Cusomized your grid columns by user themselves, allow user to hide/show columns or re-order the columns sequences.

Sample Picture

The final result look like below, you can hide/show any columns. You can type the order to re-sort the columns after save the config. You can input -1 to put it in first columns. After save, the index will reorder from 1 to the max.

The export to excel function will affected by the final resorted columns in case you use my export grid to excel extends hzlexportgrid too, Since that export extention just depends on the grid columns configs, and that columns been customized by user themselves just now.

Sample Picture

Add code in controller

Below code will help you save user configs or reset it and redirect to the destination

Some helper function list details in last session, you can deep dive HzlUtil::xxxFunction later

//your other controller code
if (isset($_POST['columnsVisibleConfigArr'])) {
            HzlUtil::saveConfigColumns(NPIPartRegion::BuyerViewColumnSetting, $_POST['columnsVisibleConfigArr']);
            //we need save to user config
        }
        if (isset($_POST['resetColumnsVisibleConfigArr'])) {
//            HzlUtil::dump($_POST['resetColumnsVisibleConfigArr']);
            HzlUtil::deleteConfigColumns(NPIPartRegion::BuyerViewColumnSetting);
            $this->redirect(array("NPIPartRegion/searchNPI"));//you can set to your index file
        }

Add code in model

I assume your grid column get from your model. such as $model->yourGridColumn() instead input in your view file directly.

public function BuyerColumns($specificId)
    {
//you can ignore/remove $specificId parameter, it just use in my own code:)
        $columnsByRole =  array(
//'id',
//'Part_Id',
            'id',
//            'Is_Primary',
            array(
                'name' => 'Is_Primary',
                'header' => 'Is_Primary',
                'value' => '$data->Is_Primary==1?"Yes":"No"',
                'filter' => NPIPart::itemAlias('Yes_No'),
                'cssClassExpression' => '$data->Is_Primary==1?"green":"grey"'
            ),
//... many other arrays
'Note',
            'Platform_GSM_Note',
//    'Update_At',
            array('name' => 'Create_At', 'header' => 'Region_Create_At')
        );

//Need read columns settings
//This is the key codes, it try to get existing configs, and try to merge into current grid columns
        $settings = Yii::app()->settings;
        $userId = "User" . yii::app()->user->id;
        $configColumns = $settings->get($userId, NPIPartRegion::BuyerViewColumnSetting);
        //and adjust default grid columns by the saved customized columns settings.
        $columnsByRole = HzlUtil::mergeConfigColumns($columnsByRole, $configColumns);
        return $columnsByRole;
}

Adjust your view code

So, you complete adjust your controller, and model, not it is the time to adjust your view code.

It is quite similar as search funtion, you click the "Config Column" link, it will expand the columns for user to setting, click the save config button, will adjust grid immediately

a.Register JS

Add below code into view file, it try to register the JS. Note, the #npipart-region-grid id need change to your own grid id. You can paste below code right after your old JS code in your view file

Yii::app()->clientScript->registerScript('config-columns', "
$('.config-columns-button').click(function(){
	$('.config-columns').toggle();
	return false;
});
$('.config-columns form').submit(function(){
	$('#npipart-region-grid').yiiGridView('update', {
		data: $(this).serialize()
	});
        $('.config-columns').toggle();
        //return false;
});
");

$columnsByRole = $model->BuyerColumns($specificId);

$columnsByRole will use in your grid. The parameter $specificID you can ignore or remove. $model->BuyerColumns($specificId) defined before, you can replace by your own get columns function:) just need to do some special handles in that function. It state before, let me highlight again below:

//your get column function need add below at the end
        $settings = Yii::app()->settings;
        $userId = "User" . yii::app()->user->id;
        $configColumns = $settings->get($userId, NPIPartRegion::BuyerViewColumnSetting);
        //and adjust default grid columns by the saved customized columns settings.
        $columnsByRole = HzlUtil::mergeConfigColumns($columnsByRole, $configColumns);
        return $columnsByRole;

b.Show Config Columns link

Add below code under the search link, it try to show the "Config Columns" link. You can adjust style by yourself, just need keep that 'class' => 'config-columns-button'

<?php echo str_repeat("&nbsp",10).CHtml::link('<b><font color = "red"> </font>Config Columns<font color = "red"> </font></b>', '#', array('class' => 'config-columns-button')); ?>

c.Add partial render code in your view file

Usually you have search code in your view file, please add below config columns code right after it. It try to partial render the _columnsVisibleConfig.php .

<div class="config-columns" style="display:none" >
    <!--<div class="search-form1" >-->
    <?php
    $this->renderPartial('_columnsVisibleConfig', array(
        'model' => $model,
        'columnsVisibleConfigArr'=>HzlUtil::getConfigColumns($columnsByRole),
        'gridLength' => 14  //you can adjust the number here, for example in case 54 columns, then the config will show as 4 grids, since 14*4=56 > 54.  Thanks.
    ));
    ?>
</div><!-- search-form -->


//other your codes
//your grid may be like below
$this->widget(
        'bootstrap.widgets.TbExtendedGridView', array(
    'id' => 'npipart-region-grid',
    'filter' => $model,
    'fixedHeader' => true,
    'type' => 'bordered hover',
    //'headerOffset' => 40,
    // 40px is the height of the main navigation at bootstrap
    'dataProvider' => $model->search(true, $specificId),
    'template' => "{pager}{summary}{items}{summary}{pager}",
    'enablePagination' => true,
    'columns' => $columnsByRole,  //note here, we use the columns which been handled in advance.
    'pager' => array(
        'class' => 'bootstrap.widgets.TbPager',
        'displayFirstAndLast' => true,
    ),
        )
);


d.That partial render real file

Usually it put in your view folder, name as _columnsVisibleConfig.php And then you can partial render this file in your view file.

<?php
$tempGridLength = $gridLength; 
?>

<div class="form">
    <div class="span18" style="font-size:83%">
        <?php
        echo CHtml::beginForm();
        $tempJ = 0;
        foreach ($columnsVisibleConfigArr as $tempI => $tempItem):
            if ($tempJ % $tempGridLength == 0) { //echo grid head
                echo '
                <div class="span3">
                <div class="grid-view">
                <table class="items" >
                <tr>
                    <th style="width:20%">Order#</th>
                    <th>Column Name</th>
                    <th>Hide</th>
                </tr>';
            }
            if ($tempJ % 2 == 0)
        {echo '<tr class = "even" style = "height:80%" > ';}
            else
        {echo '<tr class = "odd" style = "height:80%">';}
            ?>
            <td ><?php echo CHtml::textField("columnsVisibleConfigArr[$tempI][order]", $tempItem["order"], ['min' => 1, 'max' => 100, 'style'=>"width:30%;font-size:83%"]); ?></td>
            <td ><?php echo CHtml::textField("columnsVisibleConfigArr[$tempI][name]",$tempItem["name"],['readonly'=>'readonly','style'=>"width:80%;font-size:83%" ]); ?></td>
            <td><?php echo CHtml::checkBox("columnsVisibleConfigArr[$tempI][hide]",$tempItem["hide"],[]) ?></td>
            </tr>
            <?php
            $tempJ += 1;
            if ($tempJ == $tempGridLength) {
            echo '
                </table>
                </div>'.
                                CHtml::submitButton('Save Column Config',['style'=>"width:50%;font-size:83%"]).'
                </div> ';
                $tempJ = 0;
          }
        endforeach;
        if ($tempJ <> $tempGridLength) {
            echo '
                </table>
                </div>' .
                CHtml::submitButton('Save Column Config',['style'=>"width:50%;font-size:83%"]) . '
                </div> ';
        }
        ?>
        <?php

        echo str_repeat("&nbsp",10)."<font color = 'red'>Reset to Default Columns Config?! </font>".CHtml::checkBox("resetColumnsVisibleConfigArr",false,[]);
        echo CHtml::endForm(); ?>
    </div>
</div>

Some Help Functions

You can put it in your public component file or other file which you can access later. In my example, I put into components/HzlUtil.php file

// get columns name form gived grid columns
    public static function getConfigColumns($columns = [])
    {
        if (!is_array($columns)) {
            return [];
        }
        $columnsVisibleConfigArr = [];
        foreach ($columns as $i => $item) {
            $thisColumn = [];
            if (is_array($item)) {
                if (isset($item['header'])) {
                    $thisColumn['name'] = str_replace("&nbsp", "", $item['header']);
                } elseif (isset($item['name'])) {
                    $thisColumn['name'] = $item['name'];
                }
                if (isset($item['visible'])) {
                    $thisColumn['hide'] = !$item['visible'];
                } else {
                    $thisColumn['hide'] = false;
                }
            } else {
                $thisColumn['name'] = $item;
                $thisColumn['hide'] = false;
            }
            $thisColumn['order'] = $i + 1;

            $columnsVisibleConfigArr[] = $thisColumn;
        }
        return $columnsVisibleConfigArr;
    }


//we leverage CmsSettings extension to save configs to DB.  Detail info like below, you can search from Yii forum to install in your yii1.0 system in advance. Thanks.
//Actually, I just copy that file in components folder
/**
 * CmsSettings
 * 
 * @package OneTwist CMS  
 * @author twisted1919 (cristian.serban@onetwist.com)
 * @copyright OneTwist CMS (www.onetwist.com)
 * @version 1.2
 * @since 1.0
 * @access public
 *
 * 1.1e - Special thanks to Gustavo (http://www.yiiframework.com/forum/index.php?/user/6112-gustavo/)
 */

    public static function saveConfigColumns($gridCategory = '', $gridConfig = [])
    {
        usort($gridConfig, function ($a, $b) {
            $al = intval($a["order"]);
            $bl = intval($b["order"]);
            return $al == $bl ? 0 : ($al > $bl ? 1 : -1);
        });
        foreach ($gridConfig as $i => $item) {
            $gridConfig[$i]["order"] = $i + 1;
            if (!isset($item["hide"])) {
                $gridConfig[$i]["hide"] = false;
            } else if ($item["hide"]) {
                $gridConfig[$i]["hide"] = true;
            }
        }
//we leverage the CmsSettings extention here
        $settings = Yii::app()->settings;
        $userId = "User" . yii::app()->user->id;
        $settings->set($userId, $gridCategory, $gridConfig);
    }

    public static function deleteConfigColumns($gridCategory = ''){
        $settings = Yii::app()->settings;
        $userId = "User" . yii::app()->user->id;
        $settings->delete($userId, $gridCategory);
        HzlUtil::setMsg("Success Delete Config","Success delete the columns config.");
    }

    //  configColumns: each item contain order,name,hid fields
    public static function mergeConfigColumns($defaultColumns, $configColumns)
    {
        if (empty($configColumns)) {
            return $defaultColumns;
        } else {
            $FinalColumnsByRole = [];
            foreach ($configColumns as $i => $item) {
                foreach ($defaultColumns as $j => $defaultItem) {
                    $thisDefaultItemName = 'NotExistingN/A';
                    if (is_array($defaultItem)) {
                        if (isset($defaultItem['header'])) {
                            $thisDefaultItemName = str_replace("&nbsp", "", $defaultItem['header']);
                        } elseif (isset($defaultItem['name'])) {
                            $thisDefaultItemName = $defaultItem['name'];
                        }
                    } else {
                        $thisDefaultItemName = $defaultItem;
                    }
                    if ($thisDefaultItemName == $item['name']) {//find that column
                        if ($item['hide']) {
                            if (is_array($defaultItem)) {
                                $defaultItem['visible'] = false;
                                $FinalColumnsByRole[] = $defaultItem;
                            } else {
                                $newDefaultItem = [];
                                $newDefaultItem['name'] = $defaultItem;
                                $newDefaultItem['visible'] = false;
                                $FinalColumnsByRole[] = $newDefaultItem;
                            }
                        } else {
                            $FinalColumnsByRole[] = $defaultItem;
                        }
                        unset($defaultColumns[$j]);//this is important
                        break;
                    }
                }
            }
            //need append left default to final columns
            foreach ($defaultColumns as $j => $defaultItem) {
                $FinalColumnsByRole[] = $defaultItem;
            }
            return $FinalColumnsByRole;
        }
    }