Code:
Ext.Loader.setConfig({enabled: true});
Ext.Loader.setPath('Ext.ux', '../ux/');
Ext.require([
'Ext.grid',
'Ext.data.*',
'Ext.util.*',
'Ext.grid.PagingScroller'
]);
Ext.define('Employee', {
extend: 'Ext.data.Model',
fields: [
{name: 'id', type:'int'},
{name: 'rating', type: 'int'},
{name: 'salary', type: 'float'},
{name: 'name'}
]
});
Ext.onReady(
function()
{
// Returns an array of fake data
// @param {Number} count The number of fake rows to create data for
// @return {Array} The fake record data, suitable for usage with an ArrayReader
function createFakeData(count) {
var firstNames = ['Ed', 'Tommy', 'Aaron', 'Abe', 'Jamie', 'Adam', 'Dave', 'David', 'Jay', 'Nicolas', 'Nige'],
lastNames = ['Spencer', 'Maintz', 'Conran', 'Elias', 'Avins', 'Mishcon', 'Kaneda', 'Davis', 'Robinson', 'Ferrero', 'White'],
ratings = [1, 2, 3, 4, 5],
salaries = [100, 400, 900, 1500, 1000000];
var data = [];
for (var i = 0; i < (count || 25); i++) {
var ratingId = Math.floor(Math.random() * ratings.length),
salaryId = Math.floor(Math.random() * salaries.length),
firstNameId = Math.floor(Math.random() * firstNames.length),
lastNameId = Math.floor(Math.random() * lastNames.length),
rating = ratings[ratingId],
salary = salaries[salaryId],
name = Ext.String.format("{0} {1}", firstNames[firstNameId], lastNames[lastNameId]);
data.push({
id: data.length + 1,
rating: rating,
salary: salary,
name: name
});
}
return data;
}
// create the Data Store
var store = Ext.create('my.BufferedLocalStore', {
id: 'store',
model: 'Employee',
proxy: {
type: 'memory'
}
});
var grid = Ext.create(
'Ext.grid.Panel',
{
id:'myGrid',
width: 700,
height: 500,
title: 'Buffered Grid of 5,000 random records',
store: store,
verticalScroller: {
xtype: 'paginggridscroller',
activePrefetch: false
},
disableSelection: true,
invalidateScrollerOnRefresh: false,
viewConfig: {
trackOver: false
},
// grid columns
columns:[
{text: 'ID',
width: 60,
sortable: true,
dataIndex:'id'
},
{text: 'Name',
flex:1 ,
sortable: true,
dataIndex: 'name'
},
{text: 'Rating',
width: 125,
sortable: true,
dataIndex: 'rating'
},
{text: 'Salary',
width: 125,
sortable: true,
dataIndex: 'salary',
align: 'right',
renderer: Ext.util.Format.usMoney
}],
renderTo: Ext.getBody(),
dockedItems:
{xtype:'toolbar',
dock:'bottom',
items:[
{id:'f1', text:'Filter for AA',
enableToggle:true, toggleHandler:filterGrid},
{id:'f2', text:'Filter for High Rating',
enableToggle:true, toggleHandler:filterGrid},
{id:'f3', text:'Filter for Rich',
enableToggle:true, toggleHandler:filterGrid},
{text:'Clear Filters',
handler: function() {
Ext.getCmp('f1').toggle(false);
Ext.getCmp('f2').toggle(false);
Ext.getCmp('f3').toggle(false);
filterGrid();
}
},
"->",
{xtype:'tbtext', id:'dcount'}
]
}
});
var data = createFakeData(5000),
ln = data.length,
records = [],
i = 0;
for (; i < ln; i++) {
records.push(Ext.create('Employee', data[i]));
}
store.cacheRecords(records);
store.guaranteeRange(0, 49);
store.remoteSort = false;
});
function filterGrid()
{
var h = {
f1:function(r) { return r.get('name').match(/^Abe Avins/); },
f2:function(r) { return r.get('rating') == 5; },
f3:function(r) { return r.get('salary') > 200000; }
};
var keys = ['f1', 'f2', 'f3'];
var fs = keys.filter(function(k) { return Ext.getCmp(k).pressed; })
.map(function(k) { return h[k]; });
var store = Ext.getCmp('myGrid').getStore();
if (fs.length)
{
var f = function(r)
{
var pass = true;
for (var i = 0; pass && i < fs.length; ++i)
{
pass = fs[i](r);
}
return pass;
};
store.filterBy(f);
}
else
{
store.clearFilter();
}
var grid = Ext.getCmp('myGrid');
var count = grid.getStore().prefetchData.getCount();
Ext.getCmp('dcount').setText("row count: " + count);
}
Ext.define('my.BufferedLocalStore',
{
extend:'Ext.data.Store',
buffered:true,
pageSize:50,
purgePageCount:0,
remoteSort:false,
sort: function() {
var me = this,
prefetchData = me.prefetchData,
sorters,
start,
end,
range;
if (me.totalCount == prefetchData.getCount())
{
var newSorters = me.decodeSorters([arguments[0]]);
me.sorters.clear();
me.sorters.addAll(newSorters);
}
sorters = me.getSorters();
start = me.guaranteedStart;
end = me.guaranteedEnd;
if (sorters.length) {
prefetchData.sort(sorters);
range = prefetchData.getRange();
prefetchData.clear();
me.cacheRecords(range);
delete me.guaranteedStart;
delete me.guaranteedEnd;
me.guaranteeRange(start, end);
}
var parentSort = Ext.data.Store.prototype.superclass.sort;
parentSort.call(me, arguments);
},
filterBy: function(fn) {
var me = this;
var filter = new Ext.util.Filter({filterFn:fn});
me.prefetchSnapshot = me.prefetchSnapshot || me.prefetchData.clone();
me.setPrefetchData(me.prefetchSnapshot.filter([filter]));
},
clearFilter: function(suppressEvent) {
var me = this;
if (!!me.prefetchSnapshot)
{
var pfd = me.prefetchSnapshot;
delete me.prefetchSnapshot;
me.setPrefetchData(pfd, suppressEvent);
}
},
setPrefetchData:function(data, suppressEvent)
{
var me = this;
var range = data.getRange();
me.prefetchData.clear();
delete me.totalCount;
delete me.guaranteedStart;
delete me.guaranteedEnd;
me.cacheRecords(range);
me.guaranteeRange(0, me.pageSize-1);
if (suppressEvent !== true) {
me.fireEvent('datachanged', me);
me.fireEvent('refresh', me);
}
}
});
// OVERRIDE extjs 4.1 b3 functions to get buffered local data grid to work
Ext.define(
'my.Override.Table',
{
override:'Ext.panel.Table',
initComponent: function() {
var me = this;
var fixSort = me.store.buffered && !me.store.remoteSort;
var save = [];
if (fixSort) {
save = me.columns.map(function(c) { return c.sortable; });
}
// PARENT FUNCTION TURNS OFF SORTABLE FOR COLUMNS
var rv = me.callOverridden(arguments);
if (fixSort) {
Ext.Array.each(me.columns, function(c, i) { c.sortable = save[i]; });
}
return rv;
}
});
Ext.define('my.Override.grid.PagingScroller',
{
override:'Ext.grid.PagingScroller',
onViewRefresh: function() {
var me = this,
newScrollHeight,
view = me.view,
viewEl = view.el.dom,
store = me.store,
rows,
newScrollOffset,
scrollDelta,
table,
tableTop;
if (!store.getCount()) {
return;
}
// COMMENT OUT SO buffered local data WORKS
// if (store.getCount() === store.getTotalCount()) {
// return me.disabled = true;
// } else {
// me.disabled = false;
// }
me.stretcher.setHeight(newScrollHeight = me.getScrollHeight());
if (me.scrollProportion !== undefined) {
table = me.view.el.child('table', true);
me.scrollProportion = view.el.dom.scrollTop / (newScrollHeight - table.offsetHeight);
table = me.view.el.child('table', true);
table.style.position = 'absolute';
table.style.top = (me.scrollProportion ? (newScrollHeight * me.scrollProportion) - (table.offsetHeight * me.scrollProportion) : 0) + 'px';
}
else {
table = me.view.el.child('table', true);
table.style.position = 'absolute';
table.style.top = (tableTop = (store.guaranteedStart||0) * me.rowHeight) + 'px';
if (me.scrollOffset) {
rows = view.getNodes();
newScrollOffset = -view.el.getOffsetsTo(rows[me.commonRecordIndex])[1];
scrollDelta = newScrollOffset - me.scrollOffset;
me.position = (view.el.dom.scrollTop += scrollDelta);
}
else if ((tableTop > viewEl.scrollTop) || ((tableTop + table.offsetHeight) < viewEl.scrollTop + viewEl.clientHeight)) {
me.position = viewEl.scrollTop = tableTop;
}
}
}
});