Implemented the server-side data access. Added automatic POSTing of client-memory data source data. Updated documentation. Minor fixes in the drop-down cell processor.
This commit is contained in:
parent
bffd4574b6
commit
c6eb544101
|
|
@ -43,7 +43,8 @@ class TableClientMemoryDataSource extends TableDataSourceBase
|
|||
* Return records from the data source.
|
||||
* @param integer $offset Specifies the offset of the first record to return, zero-based.
|
||||
* @param integer $count Specifies the number of records to return.
|
||||
* @return array
|
||||
* @return array Returns the records.
|
||||
* If there are no more records, returns an empty array.
|
||||
*/
|
||||
public function getRecords($offset, $count)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,10 +6,15 @@
|
|||
abstract class TableDataSourceBase
|
||||
{
|
||||
/**
|
||||
* @var Specifies a name of record's key column
|
||||
* @var string Specifies a name of record's key column
|
||||
*/
|
||||
protected $keyColumn;
|
||||
|
||||
/**
|
||||
* @var integer Internal record offset
|
||||
*/
|
||||
protected $offset = 0;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
* @param string $keyColumn Specifies a name of the key column.
|
||||
|
|
@ -43,7 +48,31 @@ abstract class TableDataSourceBase
|
|||
* Return records from the data source.
|
||||
* @param integer $offset Specifies the offset of the first record to return, zero-based.
|
||||
* @param integer $count Specifies the number of records to return.
|
||||
* @return array
|
||||
* @return array Returns the records.
|
||||
* If there are no more records, returns an empty array.
|
||||
*/
|
||||
abstract public function getRecords($offset, $count);
|
||||
|
||||
/**
|
||||
* Rewinds the the data source to the first record.
|
||||
* Use this method with the readRecords() method.
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->offset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a set of records from the data source.
|
||||
* @param integer $count Specifies the number of records to return.
|
||||
* @return array Returns the records.
|
||||
* If there are no more records, returns an empty array.
|
||||
*/
|
||||
public function readRecords($count = 10)
|
||||
{
|
||||
$result = $this->getRecords($this->offset, $count);
|
||||
$this->offset += count($result);
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
<?php namespace Backend\Widgets;
|
||||
|
||||
use Input;
|
||||
use Request;
|
||||
use Backend\Classes\WidgetBase;
|
||||
use System\Classes\SystemException;
|
||||
|
||||
|
|
@ -57,6 +58,16 @@ class Table extends WidgetBase
|
|||
throw new SystemException(sprintf('The Table widget data source class "%s" is could not be found.', $dataSourceClass));
|
||||
|
||||
$this->dataSource = new $dataSourceClass($this->recordsKeyColumn);
|
||||
|
||||
if (Request::method() == 'POST' && $this->isClientDataSource()) {
|
||||
$requestDataField = $this->alias.'TableData';
|
||||
|
||||
if (Request::exists($requestDataField)) {
|
||||
// Load data into the client memory data source on POST
|
||||
$this->dataSource->purge();
|
||||
$this->dataSource->initRecords(Request::input($requestDataField));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -85,7 +96,7 @@ class Table extends WidgetBase
|
|||
$this->vars['columns'] = $this->prepareColumnsArray();
|
||||
$this->vars['recordsKeyColumn'] = $this->recordsKeyColumn;
|
||||
|
||||
$isClientDataSource = $this->dataSource instanceof \Backend\Classes\TableClientMemoryDataSource;
|
||||
$isClientDataSource = $this->isClientDataSource();
|
||||
|
||||
$this->vars['clientDataSourceClass'] = $isClientDataSource ? 'client' : 'server';
|
||||
$this->vars['data'] = $isClientDataSource ?
|
||||
|
|
@ -132,6 +143,11 @@ class Table extends WidgetBase
|
|||
return $result;
|
||||
}
|
||||
|
||||
protected function isClientDataSource()
|
||||
{
|
||||
return $this->dataSource instanceof \Backend\Classes\TableClientMemoryDataSource;
|
||||
}
|
||||
|
||||
/*
|
||||
* Event handlers
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -78,6 +78,8 @@ The options below are listed in the JavaScript notation. Corresponding data attr
|
|||
- `columns` - column definitions in JSON format, see the server-side column definition format below.
|
||||
- `rowSorting` - enables the drag & drop row sorting. The sorting cannot be used with the pagination (`recordsPerPage` is not `null` or `false`).
|
||||
- `keyColumn` - specifies the name of the key column. The default value is **id**.
|
||||
- `postback` - post the client-memory data source data to the server automatically when the parent form gets submitted. The default value is `true`. The option is used only with client-memory data sources. When enabled, the data source data is available in the widget's server-side data source: `$table->getDataSource()->getRecords();` The data postback occurs only of the request handler name matches the `postbackHandlerName` option value.
|
||||
- `postbackHandlerName` - AJAX data handler name for the automatic data postback. The data will be posted only when the AJAX requests posts data to this handler. The default value is **onSave**.
|
||||
|
||||
## Client-side helper classes
|
||||
|
||||
|
|
@ -233,4 +235,22 @@ $dataSource->purge();
|
|||
|
||||
## Reading data from the data source
|
||||
|
||||
TODO
|
||||
The server-side data sources (PHP) automatically maintain the actual data, but that mechanism for the client-memory and server-memory data sources is different.
|
||||
|
||||
In case of the client-memory data source, the table widget adds the data records to the POST, when the form is saved (see `postback` and `postbackHandlerName` options). On the server side the data is inserted to the data source by the table widget.
|
||||
|
||||
The server-memory data source always automatically maintain its contents in synch with the client using AJAX, and POSTing data is not required.
|
||||
|
||||
In PHP reading data from a data source of any type looks like this (it should be in the AJAX handler that saves the data, for the client-memory data source the handler name should match the `postbackHandlerName` option value):
|
||||
|
||||
```
|
||||
public function onSave()
|
||||
{
|
||||
// Assuming that the widget was initialized in the
|
||||
// controller constructor with the "table" alias.
|
||||
$dataSource = $this->widget->table->getDataSource();
|
||||
|
||||
while ($records = $dataSource->readRecords(5)) {
|
||||
traceLog($records);
|
||||
}
|
||||
```
|
||||
|
|
@ -136,5 +136,9 @@
|
|||
}).indexOf(parseInt(key))
|
||||
}
|
||||
|
||||
Client.prototype.getAllData = function() {
|
||||
return this.data
|
||||
}
|
||||
|
||||
$.oc.table.datasource.client = Client
|
||||
}(window.jQuery);
|
||||
|
|
@ -57,6 +57,9 @@
|
|||
this.clickHandler = this.onClick.bind(this)
|
||||
this.keydownHandler = this.onKeydown.bind(this)
|
||||
|
||||
if (this.options.postback && this.options.clientDataSourceClass == 'client')
|
||||
this.formSubmitHandler = this.onFormSubmit.bind(this)
|
||||
|
||||
// Navigation helper
|
||||
this.navigation = null
|
||||
|
||||
|
|
@ -122,6 +125,9 @@
|
|||
Table.prototype.registerHandlers = function() {
|
||||
this.el.addEventListener('click', this.clickHandler)
|
||||
this.el.addEventListener('keydown', this.keydownHandler)
|
||||
|
||||
if (this.options.postback && this.options.clientDataSourceClass == 'client')
|
||||
this.$el.closest('form').bind('oc.beforeRequest', this.formSubmitHandler)
|
||||
}
|
||||
|
||||
Table.prototype.unregisterHandlers = function() {
|
||||
|
|
@ -130,6 +136,11 @@
|
|||
|
||||
this.el.removeEventListener('keydown', this.keydownHandler);
|
||||
this.keydownHandler = null
|
||||
|
||||
if (this.formSubmitHandler) {
|
||||
this.$el.closest('form').unbind('oc.beforeRequest', this.formSubmitHandler)
|
||||
this.formSubmitHandler = null
|
||||
}
|
||||
}
|
||||
|
||||
Table.prototype.initCellProcessors = function() {
|
||||
|
|
@ -331,6 +342,10 @@
|
|||
|
||||
this.commitEditedRow()
|
||||
this.activeCellProcessor = null
|
||||
|
||||
if (this.activeCell)
|
||||
this.activeCell.setAttribute('class', '')
|
||||
|
||||
this.activeCell = null
|
||||
}
|
||||
|
||||
|
|
@ -466,6 +481,17 @@
|
|||
)
|
||||
}
|
||||
|
||||
Table.prototype.notifyRowProcessorsOnChange = function(cellElement) {
|
||||
var columnName = cellElement.getAttribute('data-column'),
|
||||
row = cellElement.parentNode
|
||||
|
||||
for (var i = 0, len = row.children.length; i < len; i++) {
|
||||
var column = this.options.columns[i].key
|
||||
|
||||
this.cellProcessors[column].onRowValueChanged(columnName, row.children[i])
|
||||
}
|
||||
}
|
||||
|
||||
// EVENT HANDLERS
|
||||
// ============================
|
||||
|
||||
|
|
@ -522,14 +548,10 @@
|
|||
return
|
||||
}
|
||||
|
||||
Table.prototype.notifyRowProcessorsOnChange = function(cellElement) {
|
||||
var columnName = cellElement.getAttribute('data-column'),
|
||||
row = cellElement.parentNode
|
||||
|
||||
for (var i = 0, len = row.children.length; i < len; i++) {
|
||||
var column = this.options.columns[i].key
|
||||
|
||||
this.cellProcessors[column].onRowValueChanged(columnName, row.children[i])
|
||||
Table.prototype.onFormSubmit = function(ev, data) {
|
||||
if (data.handler == this.options.postbackHandlerName) {
|
||||
this.unfocusTable()
|
||||
data.options.data[this.options.alias + 'TableData'] = this.dataSource.getAllData()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -683,7 +705,9 @@
|
|||
clientDataSourceClass: 'client',
|
||||
keyColumn: 'id',
|
||||
recordsPerPage: false,
|
||||
data: null
|
||||
data: null,
|
||||
postback: true,
|
||||
postbackHandlerName: 'onSave'
|
||||
}
|
||||
|
||||
// TABLE PLUGIN DEFINITION
|
||||
|
|
|
|||
|
|
@ -75,9 +75,8 @@
|
|||
|
||||
this.fetchOptions(cellContentContainer.parentNode, function renderCellFetchOptions(options) {
|
||||
if (options[value] !== undefined)
|
||||
value = options[value]
|
||||
viewContainer.textContent = options[value]
|
||||
|
||||
viewContainer.textContent = value
|
||||
cellContentContainer.setAttribute('tabindex', 0)
|
||||
})
|
||||
}
|
||||
|
|
@ -113,7 +112,6 @@
|
|||
|
||||
this.hideDropdown()
|
||||
this.itemListElement = null
|
||||
|
||||
this.activeCell = null
|
||||
}
|
||||
|
||||
|
|
@ -178,6 +176,13 @@
|
|||
|
||||
var activeItemElement = this.itemListElement.querySelector('ul li.selected')
|
||||
|
||||
if (!activeItemElement) {
|
||||
activeItemElement = this.itemListElement.querySelector('ul li:first-child')
|
||||
|
||||
if (activeItemElement)
|
||||
activeItemElement.setAttribute('class', 'selected')
|
||||
}
|
||||
|
||||
if (activeItemElement) {
|
||||
window.setTimeout(function(){
|
||||
activeItemElement.focus()
|
||||
|
|
|
|||
Loading…
Reference in New Issue