Add change monitoring to Grid widget

This commit is contained in:
Sam Georges 2014-07-18 19:16:23 +10:00
parent a2e755e439
commit baec411fd3
5 changed files with 101 additions and 19 deletions

View File

@ -51,20 +51,25 @@ class Grid extends WidgetBase
protected $disableToolbar = false;
/**
* @var array Provided data set
* @var array Provided data set, cannot use with dataLocker or useDataSource.
*/
protected $data;
/**
* @var boolean Use a remote data source
*/
protected $useDataSource;
/**
* @var string HTML element that can [re]store the grid data.
* @var string HTML element that can [re]store the grid data, cannot use with data or useDataSource.
*/
protected $dataLocker;
/**
* @var boolean Get data from AJAX callback (onDataSource), cannot use with data or dataLocker.
*/
protected $useDataSource = false;
/**
* @var boolean Sends an AJAX callback (onDataChanged) any time a field is changed.
*/
protected $monitorChanges = true;
/**
* Initialize the widget, called by the constructor and free from its parameters.
*/
@ -78,6 +83,7 @@ class Grid extends WidgetBase
$this->data = $this->getConfig('data', $this->data);
$this->dataLocker = $this->getConfig('dataLocker', $this->dataLocker);
$this->useDataSource = $this->getConfig('useDataSource', $this->useDataSource);
$this->monitorChanges = $this->getConfig('monitorChanges', $this->monitorChanges);
}
/**
@ -106,6 +112,7 @@ class Grid extends WidgetBase
$this->vars['data'] = $this->data;
$this->vars['dataLocker'] = $this->dataLocker;
$this->vars['useDataSource'] = $this->useDataSource;
$this->vars['monitorChanges'] = $this->monitorChanges;
}
protected function makeToolbarWidget()
@ -137,6 +144,19 @@ class Grid extends WidgetBase
return ['result' => $result];
}
public function onDataChanged()
{
if (!$this->monitorChanges)
return;
/*
* Changes array, each array item will contain:
* ['rowData' => [...], 'keyName' => 'changedColumn', 'oldValue' => 'was', 'newValue' => 'is']
*/
$changes = post('changes');
$this->fireEvent('grid.dataChanged', [$changes]);
}
public function onDataSource()
{
if (!$this->useDataSource)

View File

@ -3,13 +3,16 @@
*
* Data attributes:
* - data-control="datagrid" - enables the plugin on an element
* - data-option="value" - an option with a value
* - data-allow-remove="true" - allow rows to be removed
* - data-autocomplete-handler="onAutocomplete" - AJAX handler for autocomplete values
* - data-data-locker="input#locker" - Input element to store and restore grid data as JSON
* - data-source-handler="onGetData" - AJAX handler for obtaining grid data
*
* JavaScript API:
* $('a#someElement').dataGrid({ option: 'value' })
* $('div#someElement').dataGrid({ option: 'value' })
*
* Dependences:
* - Some other plugin (filename.js)
* Dependences:
* - Handsontable (handsontable.js)
*/
+function ($) { "use strict";
@ -43,6 +46,19 @@
// rowHeaders: false,
// manualColumnMove: true,
// manualRowMove: true,
afterChange: function(changes, source) {
if (source === 'loadData')
return
/*
* changes - is a 2D array containing information about each of the edited cells
* [ [row, prop, oldVal, newVal], ... ].
*
* source - is one of the strings: "alter", "empty", "edit", "populateFromArray",
* "loadData", "autofill", "paste".
*/
self.$el.trigger('datagrid.change', [changes, source])
},
fillHandle: false,
multiSelect: false,
removeRowPlugin: this.options.allowRemove
@ -51,18 +67,24 @@
if (this.options.autoInsertRows)
handsontableOptions.minSpareRows = 1
/*
* Data provided
*/
if (this.options.data) {
handsontableOptions.data = this.options.data
}
/*
* Data from a data locker
*/
else if (this.options.dataLocker) {
/*
* Event to update the data locker
*/
this.$dataLocker = $(this.options.dataLocker)
handsontableOptions.afterChange = function(changes, source) {
self.$el.on('datagrid.change', function(event, eventData) {
if (!self.gridInstance) return
self.$dataLocker.val(JSON.stringify(self.getData()))
}
})
/*
* Populate existing data
@ -74,10 +96,44 @@
delete handsontableOptions.data
}
}
/*
* Data from an AJAX data source
*/
else if (this.options.sourceHandler) {
self.refreshDataSource()
}
/*
* Monitor for data changes
*/
if (this.options.changeHandler) {
self.$el.on('datagrid.change', function(event, changes, source) {
var changeData = [];
$.each(changes, function(index, change){
var changeObj = {}
changeObj.keyName = change[1]
changeObj.oldValue = change[2]
changeObj.newValue = change[3]
if (changeObj.oldValue == changeObj.newValue)
return; // continue
changeObj.rowData = self.getDataAtRow(change[0])
changeData.push(changeObj)
})
if (changeData.length > 0) {
self.$el.request(self.options.changeHandler, {
data: { changes: changeData }
})
}
})
}
/*
* Create up Handson table and validate columns
*/
this.$el.handsontable(handsontableOptions)
this.gridInstance = this.$el.handsontable('getInstance')
@ -105,6 +161,9 @@
return columns
}
/*
* Auto complete
*/
var autocompleteLastQuery = '',
autocompleteInterval = 300,
autocompleteInputTimer
@ -142,6 +201,7 @@
data: null,
dataLocker: null,
sourceHandler: null,
changeHandler: null,
startRows: 1,
minRows: 1,
autoInsertRows: false,

View File

@ -124,9 +124,6 @@
.handsontable tbody th:last-of-type {
border-right: 1px solid #e2e2e2 !important;
}
.handsontable tbody td:first-of-type.currentRow {
border-left: 3px solid #ff9933;
}
.handsontable th.active {
/*background-color: #CCC;*/
color: #666;

View File

@ -147,9 +147,13 @@
border-right: 1px solid @color-handsontable-border !important;
}
td:first-of-type.currentRow {
border-left: 3px solid @color-list-stripe-active;
}
//td:first-of-type {
// border-left: 3px solid transparent;
//}
// td:first-of-type.currentRow {
// border-left: 3px solid @color-list-stripe-active;
// }
}
th.active {

View File

@ -12,6 +12,7 @@
data-autocomplete-handler="<?= $this->getEventHandler('onAutocomplete') ?>"
<?php if ($dataLocker): ?>data-data-locker="<?= $dataLocker ?>"<?php endif ?>
<?php if ($useDataSource): ?>data-source-handler="<?= $this->getEventHandler('onDataSource') ?>"<?php endif ?>
<?php if ($monitorChanges): ?>data-change-handler="<?= $this->getEventHandler('onDataChanged') ?>"<?php endif ?>
></div>
</div>