yii-react-gridview
Version:
React render of Yii gridview
177 lines (163 loc) • 9.26 kB
Markdown
# Yii2 GridView widget for react
This component is created to simplify moving from php rendering of built-in [Yii2 Gridview widget](https://www.yiiframework.com/doc/api/2.0/yii-grid-gridview) to React-based application using some of its familiar settings.
[Simple example](https://codepen.io/sufitman/project/editor/XVamYV)
## Installing
```bash
npm install --save yii-react-gridview
```
## Setting `props`
Instead of using `pager` or `dataProvider` objects as it used in [Yii2 Gridview widget](https://www.yiiframework.com/doc/api/2.0/yii-grid-gridview), some of its properties (or equivalents) should be set as props directly in GridView component. It makes more suitable way for React of re-rendering the component in case if some prop will be changed. See [Available props](#available-props) to find out how to set up your GridView.
## Example
of component:
```jsx
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import GridView from 'yii-react-gridview';
import Axios from 'axios';
class App extends Component {
constructor (props) {
super(props);
this.state = {
data: null,
};
Axios.get('/your/get-data').then(response => {
let dataProvider = response.data;
this.pageSize = dataProvider.pageSize;
this.headerCells = dataProvider.headerCells;
this.maxButtonCount = dataProvider.maxButtonCount;
this.setState({
data: dataProvider.data,
currentPage: dataProvider.currentPage,
totalCount: dataProvider.totalCount,
});
});
this.columns = {
username: null,
email: null,
city: null,
}
}
onPageButtonClicked = (currentPage) => {
Axios.get('/your/get-data').then(response => {
this.setState({
currentPage: currentPage,
//...
});
})
};
onSortChanged = (sort) => {
this.setState({sort: sort});
Axios.get('/your/get-data', {
params: {
// Pass 'sort' as is (js-object) or prepare it to be compatible with Query::orderBy()
orderBy: sort,
//...
}
}).then(response => {
this.setState({
//...
});
});
};
render() {
return (
<div className="App">
<GridView
data={ this.state.data }
headerCells={ this.headerCells }
columns={ this.columns }
currentPage={ this.state.currentPage }
totalCount={this.state.totalCount}
maxButtonCount={ this.maxButtonCount }
pageSize={this.pageSize }
onPageButtonClick={ this.onPageButtonClicked }
onSortChange={ this.onSortChanged }
/>
</div>
);
}
}
ReactDOM.render(<App/>, document.getElementById('root'));
```
of action:
```php
class YourController extends Controller {
public function actionGetData($currentPage = 0, $pageSize = 20, $filters = [], $orderBy = '') {
\Yii::$app->response->format = Response::FORMAT_JSON;
// Prepare orderBy object here or do it in 'onSortChange' callback
// Anyway make it compatible with '->orderBy($orderBy)'
$preparedOrderBy = [];
if ($orderBy) {
foreach (Json::decode($orderBy) as $col => $sort) {
$preparedOrderBy[] = "{$col} {$sort}";
}
if (!empty($preparedOrderBy)) {
$preparedOrderBy = implode(',', $preparedOrderBy);
}
}
// Probably $filters should be also prepared
// ...
return [
'data' => ArrayHelper::toArray(User::find()
->andFilterWhere($filters)
->offset($currentPage * $pageSize)
->orderBy($preparedOrderBy)
->limit($pageSize)
->all(), [
User::class => [
'username',
'email',
'city',
]
]),
'headerCells' => (new User)->attributeLabels(),
'currentPage' => (int) $currentPage,
'totalCount' => (int) User::find()->andFilterWhere($filters)->count(),
'pageSize' => $pageSize,
];
}
}
```
## Available `props`
|Property|Type|Default value|Description|
|:---:|:---:|:---:|:---|
|`data`|Array|undefined|Array of models to show in list|
|`notSetText`|string|'(not set)'|Text will be shown when a cell in a row is not set|
|`headerCells`|Object|{}|Key-value pairs of names of data models properties. It should contain the same keys as keys of an Object in `data`.<br>Values of `headerCells` could be either strings or object of following structure: <br>` { value: 'Column Title', column: 'attrbute_name', enableSorting: true, sort: 'ASC' }`.<br>If `enableSorting` is `true` then `column` required. `sort` (if specified) must be either 'ASC' or 'DESC'|
|`footerCells`|Array|[]|Array of strings or components corresponding cells of `tfoot`-row. Make sure the array length match the table|
|`caption`|String|undefined|A string for caption if necessary|
|`emptyCaption`|String|'Nothing found'|The text will be shown when no data rows are loaded|
|`captionOptions`|Object|{}|HTML attributes of `caption`|
|`containerOptions`|Object|{}|HTML attributes of GridView instance conteiner (div that wraping the table and the pager)|
|`tableOptions`|Object|{}|HTML attributes of table|
|`showHeader`|Boolean|true|Whether show \<thead\> or not|
|`showFooter`|Boolean|false|Whether show \<tfoot\> or not|
|`hidePager`|Boolean|false|Whether show pager buttons or not|
|`placeFooterAfterBody`|Boolean|true|Whether place \<tfoot\> after body or not|
|`headerRowOptions`|Object|{}|HTML attributes of *thead > row*|
|`footerRowOptions`|Object|{}|HTML attributes of *tfoot > row*|
|`rowOptions`|Object|{}|HTML attributes of *tbody \> row*|
|`columns`|Object|undefined|Keys of the object are whether properties of a model in data (then the title will be provided by `headerCells`) or custom strings that will be a column titles.<br>Values of the object are either null (to provide a model value as is) or `function (cell, rowId, hoveredRowId)` (to decorate a model value with its result).<br>Also string `'serial'` can be set to provide models numeration.<br>If `'checkbox'` is set as a key and its value (just value at least) then column of checkboxes will be rendered in order to select row(s) ids (a value that specified in `rowIdColumn`)|
|`filters`|Object|null|Contain *filters* for specified columns. *Filters* can be:<br>a) string `'text'` renders simple input of `type="text"`;<br>b) Object `{ type: ..., options: {...} }` where type can be either `'text'` (input of `type="text"`), `'checkbox'` or `'select'`. Options typically are HTML attributes of the inputs. If type is `'select'` then `options` should contain `data` - object of options (where key is value attribute of an \<option\> and value is its text);<br>c) `function (name, onChange)` to render custom input with name={ `name` } and onChange={ `onChange` } (must return a React.Component/html) |
|`onSortChange`|`function(sort)`|undefined|Callback to sort the data with `sort` - key-value object (```js { column:'ASC' /* or 'DESC' */ }```) to sort the `data`. The way of is up to you|
|`onFilterChange`|`function(filters)`|undefined|Callback to filter the data with `filters` - key-value object to filter the `data`. **Required** when filters are specified. The way of filtering depends on you|
|`pagerOptions`|object|undefined|HTML attributes of pager container|
|`currentPage`|integer|undefined|Number of current page (begins from 0). **Should be provided by `data` provider**|
|`totalCount`|integer|undefined|Total count of models given in `data`. **Should be provided by `data` provider**|
|`maxButtonCount`|integer|10|Max count of pager links|
|`pageSize`|integer|20|Max count of models on a page|
|`pagerTag`|string|`'ul'`|Tag name of pager container|
|`pageTag`|string|`'li'`|Tag name of pager link|
|`activePageCssClass`|string|`'active'`|Class name of active page link|
|`disabledPageCssClass`|string|`'disabled'`|Class name of disabled pager link|
|`nextPageCssClass`|string|`'next'`|Class name of 'next' page link|
|`prevPageCssClass`|string|`'prev'`|Class name of 'previous' page link|
|`firstPageCssClass`|string|`'first'`|Class name of 'first' page link|
|`lastPageCssClass`|string|`'last'`|Class name of 'last' page link|
|`nextPageLabel`|string|`'»'`|Label of 'next' page link|
|`prevPageLabel`|string|`'«'`|Label of 'previous' page link|
|`firstPageLabel`|string|null|Label of 'first' page link|
|`lastPageLabel`|string|null|Label of 'last' page link|
|`onPageButtonClick`|`function(pageNumber)`|null|Callback of click on pager link with given page number. Originally it should replace `pageNumber` with its page number and reload the `data`, but it's up to you whatever it does.|
|`onSelectionChange`|`function(selectedRowIds)`|null|Callback which will be applied when a row is (or all rows are) selected. Array of selected values specified in `rowIdColumn` will be passed in `selectedRowIds`|
|`rowIdColumn`|string|'id'|Column name that could be used as primary key for selection. If `onSelectionChange` is set, then array of values of selected rowIdColumn will be passed as an argument|