Với mọi ứng dụng web, việc tìm kiếm, lọc các thông tin cần thiết là điều không thể thiếu. Gridview là danh sách được hiển thị dưới dạng lưới của 1 bảng, cho phép người sử dụng xem và theo dõi các thông tin cần thiết cũng như có thể tìm kiếm trực tiếp trên các danh sách này một cách thuận tiện và nhanh chóng.

Gridview hoạt động ra sao ?

Như tại hạ đã giới thiệu ở trên Gridview là dạng lưới, được hiển thị dưới dạng bảng. Nó cung cấp các chức năng về tìm kiếm, sắp xếp, phân trang dữ liệu.

Giống như FormInput, Gridview cũng là 1 widget. Dưới đây là đoạn code cơ bản để sử dụng Gridview trong view

<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'filterModel' => $searchModel,
    'columns' => [
        'id',
        'name',
        'created_at:datetime',
        // ...
    ],
]) ?>

- dataProvider cung cấp dữ liệu hỗ trợ việc sắp xếp, phân trang và nó được base từ 1 interface yii\data\DataProviderInterface

- columns là danh sách các cột ứng với các attributes được khai báo trong model 

filterModel hỗ trợ việc người dùng lọc thông tin ngay trên Gridview

Để đỡ khó hiểu tại hạ sẽ ví dụ về 1 Gridview của User sẽ có 2 cách như sau

- Nếu không tạo tự động Gridview thông qua CRUD thì tại hạ sẽ sử dụng như sau

Ở phía controller

<?php

namespace frontend\controllers;

use Yii;
use app\models\User;
use app\models\search\UserSearch;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use yii\data\ActiveDataProvider;


/**
 * UserController implements the CRUD actions for User model.
 */
class UserController extends Controller
{
    //.................

    public function actionShow()
    {
        $searchModel = new User();
        
        $query = User::find();


        $dataProvider = new ActiveDataProvider([
            'query' => $query,
            'sort'=> [
                'defaultOrder' => 
                [
                    'username' => SORT_ASC,
                    'created_at' => SORT_DESC,
                ]
            ],
            'pagination' => [
                'pageSize' => 1,
             ],
        ]);

        $searchModel->load(Yii::$app->request->get()); // lấy ra tất cả các giá trị được nhập trên gridview để lọc dữ liệu

        $query->andFilterWhere(['like', 'username', $searchModel->username]);
        

        return $this->render('show', [
            'searchModel' => $searchModel,
            'dataProvider' => $dataProvider,
        ]);
    }
}

Ở action trên tại hạ có khai báo dataProvider nhận vào các truy vấn lấy ra dữ liệu từ User, nếu không có thêm điều kiện lọc như trên thì dataProvider sẽ thực thi lệnh User::find()-> all(). Với việc hỗ trợ sắp xếp và phân trang, các đồng code có thể tùy chỉnh lại các thông số trên cho hợp lý.

Ở đây do dữ liệu có 2 bản ghi nên tại hạ xin mạo muội đặt phân trang mỗi page là 1 bản ghi để thấy được phân trang =)) mong anh em thông cảm. Nếu có thêm truy vấn where để lọc thì câu truy vấn sẽ được nối thêm trước khi trả về kết quả ở dataProvider để sắp xếp và phân trang (nếu có)

- Ở trường hợp thứ 2 nếu tạo từ CRUD Gii thì Gridview sẽ được tạo ra mặc định ở controller như sau

<?php

namespace frontend\controllers;

use Yii;
use app\models\User;
use app\models\search\UserSearch;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;


/**
 * UserController implements the CRUD actions for User model.
 */
class UserController extends Controller
{
    //...........................

    /**
     * Lists all User models.
     * @return mixed
     */
    public function actionIndex()
    {
        $searchModel = new UserSearch();
        $dataProvider = $searchModel->search(Yii::$app->request->queryParams);

        return $this->render('index', [
            'searchModel' => $searchModel,
            'dataProvider' => $dataProvider,
        ]);
    }

    
}

Các phần như searchModel, dataProvider được sử dụng từ model Search được tạo từ CRUD 

<?php

namespace app\models\search;

use yii\base\Model;
use yii\data\ActiveDataProvider;
use app\models\User;

/**
 * UserSearch represents the model behind the search form of `app\models\User`.
 */
class UserSearch extends User
{
   //..................
    /**
     * Creates data provider instance with search query applied
     *
     * @param array $params
     *
     * @return ActiveDataProvider
     */
    public function search($params)
    {
        $query = User::find();

        // add conditions that should always apply here

        $dataProvider = new ActiveDataProvider([
            'query' => $query,
        ]);

        $this->load($params);

        if (!$this->validate()) {
            // uncomment the following line if you do not want to return any records when validation fails
            // $query->where('0=1');
            return $dataProvider;
        }

        // grid filtering conditions
        $query->andFilterWhere([
            'id' => $this->id,
            'status' => $this->status,
            'created_at' => $this->created_at,
            'updated_at' => $this->updated_at,
        ]);

        $query->andFilterWhere(['like', 'username', $this->username])
            ->andFilterWhere(['like', 'auth_key', $this->auth_key])
            ->andFilterWhere(['like', 'password_hash', $this->password_hash])
            ->andFilterWhere(['like', 'password_reset_token', $this->password_reset_token])
            ->andFilterWhere(['like', 'email', $this->email])
            ->andFilterWhere(['like', 'verification_token', $this->verification_token]);

        return $dataProvider;
    }
}

Nhìn qua thì cũng chẳng khác so với tạo bằng tay lắm :)), dataProvider cũng được tạo từ ActiveDataProvider, phần lọc dữ liệu có vẻ đầy đủ hơn và nó sẽ chặn các truy vấn lọc không hợp lệ. Thực tế nhìn phần searchModel có vẻ khác nhau nhưng nó đều là để tạo ra 1 model User dành cho việc lọc dữ liệu.

Ngoài việc sử dụng ActiveDataProvider các đồng code có thể sử dụng các DataProvider khác tại đây 

Ở view thì tại hạ xin phép dùng bên CRUD tạo ra vì nó hỗ trợ thêm cả cột thứ tự được buid từ yii\grid\SerialColumn và các nút hành động sửa - xóa - xem được buid từ yii\grid\ActionColumn

<?php

use yii\helpers\Html;
use yii\grid\GridView;

/* @var $this yii\web\View */
/* @var $searchModel app\models\search\UserSearch */
/* @var $dataProvider yii\data\ActiveDataProvider */

$this->title = 'Users';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="user-index">

    <h1><?= Html::encode($this->title) ?></h1>

    <p>
        <?= Html::a('Create User', ['create'], ['class' => 'btn btn-success']) ?>
    </p>

    <?php // echo $this->render('_search', ['model' => $searchModel]); ?>

    <?= GridView::widget([
        'dataProvider' => $dataProvider,
        'filterModel' => $searchModel,
        'columns' => [
            ['class' => 'yii\grid\SerialColumn'],

            'id',
            'username',
            'auth_key',
            'password_hash',
            'password_reset_token',
            'email:email',
            'status',
            'created_at:datetime',
            'updated_at',
            //'verification_token',

            ['class' => 'yii\grid\ActionColumn'],
        ],
    ]); ?>


</div>

Và sẽ có kết quả như sau 

yii grid

Các input phía trên Gridview dành cho việc lọc dữ liệu và hiển thị qua dạng $_GET trên URL như sau

yii grid

 

Nếu muốn tùy chỉnh thì các đồng code có thể tùy chỉnh lại như sau 

 <?= GridView::widget([
        'dataProvider' => $dataProvider,
        'filterModel' => $searchModel,
        'columns' => [
            ['class' => 'yii\grid\SerialColumn'],

            'id',
            [
                            
                'attribute'=>'username',
                'value'=>function($data)
                {
                    return ($data->username) ? $data->name:'';
                }
            ],
            [
                            
                'attribute'=>'auth_key',
                'value'=>function($data)
                {
                    return ($data->auth_key) ? $data->auth_key:'';
                },
                'filter' => false,
                'format' => 'raw'
            ],
            [
                            
                'attribute'=>'status',
                'value'=>function($data)
                {
                    return ($data->status == 10)?'<span class="text-primary"><i class="fa fa-check"></i> Đã kích hoạt</span>':'<span class="text-danger"><i class="fa fa-ban"></i> Đang khóa</span>';
                },
                'filter' => \yii\bootstrap\Html::activeDropDownList($searchModel,'status',\yii\helpers\ArrayHelper::map([
                    ['id' =>0, 'name' => 'Đang khóa'], ['id' => 10, 'name' => 'Đã kích hoạt']
                ],'id','name'),['prompt' => 'Tất cả','class' => 'form-control']),
                'format'=>'raw'
            ],
            'password_hash',
            'password_reset_token',
            'email:email',
            'created_at:datetime',
            'updated_at',
            //'verification_token',

            ['class' => 'yii\grid\ActionColumn'],
        ],
    ]); ?>

Giải thích 1 chút, ngoài việc dùng column hiển thị bằng tên bình thường thì Gridview còn hỗ trợ cho các đồng code tùy biến qua mảng các thuộc tính của 1 cột

- attribute là tên thuộc tính - tên cột

- value là 1 dạng hàm ẩn danh trả về giá trị của cột, các đồng code có thể xử lý thêm trong hàm này sau đó return lại.

- filter là cách thức lọc, mặc đinh sẽ là true lọc bằng cách nhập vào 1 input, nếu set là false thì cột đó sẽ không cho phép lọc, có thể có nhiều kiểu dạng lọc khác như dạng dropdownList, dạng dateTimePicker....

- format là định dạng giá trị của cột đó, như trên là dạng raw tức là dạng hiển thị ở dạng thô, nếu giá trị của bạn là dạng html thì rất cần filter dạng này vì nếu không để format dạng raw thì Gridview sẽ hiển thị dạng text thường

...... còn nhiều thuộc tính khác về header, headerOption về cột trong Gridview các đồng code có thể xem thêm tại đây.

À quên còn cái thứ hay ho nhất mà tại hạ muốn giới thiệu là Pjax hỗ trợ việc tìm kiếm mà không load lại trang, không làm thay đổi URL(Nhìn Url nó thay đổi cũng hơi ngứa mắt), lợi thì lợi thật nhưng nếu nhiều người dùng mà họ muốn gửi link cho ai khác xem thì lại không có Url :)))

Dưới đây là việc áp dụng với Pjax

<?php

use yii\helpers\Html;
use yii\grid\GridView;
use yii\widgets\Pjax;
/* @var $this yii\web\View */
/* @var $searchModel app\models\search\UserSearch */
/* @var $dataProvider yii\data\ActiveDataProvider */

$this->title = 'Users';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="user-index">

    <h1><?= Html::encode($this->title) ?></h1>

    <p>
        <?= Html::a('Create User', ['create'], ['class' => 'btn btn-success']) ?>
    </p>


    <?php Pjax::begin(['enablePushState' => false,'timeout'=>false]); ?>    
        <?= GridView::widget([
            'dataProvider' => $dataProvider,
            'filterModel' => $searchModel,
            'columns' => [
                ['class' => 'yii\grid\SerialColumn'],

                'id',
                'username',
                'auth_key',
                'password_hash',
                'password_reset_token',
                'email:email',
                'status',
                'created_at:datetime',
                'updated_at',
                //'verification_token',

                ['class' => 'yii\grid\ActionColumn'],
            ],
        ]); ?>
    <?php Pjax::end(); ?>   

</div>

Để hiểu thêm về Pjax tại hạ xin phép sẽ đàm đạo thêm ở một bài khác. Trong Yii2, Pjax có rất nhiều thứ hay ho để áp dụng vào dự án thực tế mà các đồng code cần.

Tổng kết

Bài viết này tại hạ đã tổng hợp lại việc sử dụng Gridview và tìm kiếm, phân trang hay sắp xếp như nào trên Gridview. Sắp tới tại hạ sẽ giới thiệu một extension của Yii2 với Gridview sử dụng khá tiện. Bài viết có thể có sai sót trong quá trình biên soạn mong anh em thông cảm smiley.