PDA

View Full Version : [CLOSED]Grid removeAll() and PagingToolbar refreshing



markalroberts
6 Oct 2009, 9:12 AM
It would appear from the documentation that, to clear a Store, one calls removeAll().

My grid correctly refreshes to show no records.

However, the pager display message remains the same... I would have expected the emptyMsg to kick in at this point.

Am I doing something wrong, or is this a bug?

Thanks,
Mark.

Condor
7 Oct 2009, 12:56 AM
Yes, I believe this should be qualified as a bug.

Here's a fix:

Ext.override(Ext.data.Store, {
add : function(records){
records = [].concat(records);
if(records.length < 1){
return;
}
for(var i = 0, len = records.length; i < len; i++){
records[i].join(this);
}
var index = this.data.length;
this.data.addAll(records);
if(this.snapshot){
this.snapshot.addAll(records);
}
this.totalLength += records.length;
this.fireEvent('add', this, records, index);
},
remove : function(record){
if(Ext.isArray(record)){
Ext.each(record, function(r){
this.remove(r);
}, this);
}
var index = this.data.indexOf(record);
if(index > -1){
record.join(null);
this.data.removeAt(index);
if(this.pruneModifiedRecords){
this.modified.remove(record);
}
if(this.snapshot){
this.snapshot.remove(record);
}
this.totalLength--;
this.fireEvent('remove', this, record, index);
}
},
removeAll : function(){
var items = [];
this.each(function(rec){
items.push(rec);
});
this.clearData();
if(this.snapshot){
this.snapshot.clear();
}
if(this.pruneModifiedRecords){
this.modified = [];
}
this.totalLength = 0;
this.fireEvent('clear', this, items);
}
});
Ext.override(Ext.PagingToolbar, {
bindStore : function(store, initial){
var doLoad;
if(!initial && this.store){
if(store !== this.store && this.store.autoDestroy){
this.store.destroy();
}else{
this.store.un('beforeload', this.beforeLoad, this);
this.store.un('load', this.onLoad, this);
this.store.un('exception', this.onLoadError, this);
this.store.un('datachanged', this.onChange, this);
this.store.un('add', this.onChange, this);
this.store.un('remove', this.onChange, this);
this.store.un('clear', this.onClear, this);
}
if(!store){
this.store = null;
}
}
if(store){
store = Ext.StoreMgr.lookup(store);
store.on({
scope: this,
beforeload: this.beforeLoad,
load: this.onLoad,
exception: this.onLoadError,
datachanged: this.onChange,
add: this.onChange,
remove: this.onChange,
clear: this.onClear
});
doLoad = true;
}
this.store = store;
if(doLoad){
this.onLoad(store, null, {});
}
},
onLoad : function(store, r, o){
if(!this.rendered){
this.dsLoaded = [store, r, o];
return;
}
var p = this.getParams();
this.cursor = (o.params && o.params[p.start]) ? o.params[p.start] : 0;
this.onChange();
},
onChange : function(){
if(this.rendered){
var d = this.getPageData(), ap = d.activePage, ps = d.pages;
this.afterTextItem.setText(String.format(this.afterPageText, d.pages));
this.inputItem.setValue(ap);
this.first.setDisabled(ap == 1);
this.prev.setDisabled(ap == 1);
this.next.setDisabled(ap == ps);
this.last.setDisabled(ap == ps);
this.refresh.enable();
this.updateInfo();
}
this.fireEvent('change', this, d);
},
onClear : function(){
this.cursor = 0;
this.onChange();
}
});

Known issue: Fires change event twice when loading.

markalroberts
7 Oct 2009, 2:35 AM
Excellent! Thank you. Presumably this will be picked up as a bug, or do I need to do something to escalate it - would be a shame for your code not to be integrated :)

Mark.

evant
15 Oct 2009, 10:04 PM
I don't necessarily agree with this. There have been several discussions about local manipulation of a paging toolbar. There are several issues.

Say I have 20 items on the first page and I add a new record locally. What should happen? Same with removing a single record on a page of 20, should the server re-request another record from the server?

I think it's best to leave this up to the developer, PagingToolbar is really only intended for use with "remote" stores.

prometheus
23 Oct 2009, 5:37 AM
Could it be an option if dissociate the PagingToolbar to two classes, one for remote paging and to another for local paging? Remote and local data handling is too different from eachother, my point is that cannot handle all two cases in one class. So my idea to solve all of these problems to make data handling classes as abstarct classes, then make - for example - a LocalStore and a RemoteStore, etc..., LocalPagingStore and RemotePagingStore.

I haven`t know a case in practise that handle a recordset locally and remotly in the same time, all data handling should only locally or remotly.

Separating these two cases can results a clearest interface I think.

What do you think about this option? Is this a way?

Condor
23 Oct 2009, 5:44 AM
You could extend PagingToolbar instead of overriding it.

Also, my PagingStore user extension (for local paging) doesn't need the add/remove/removeAll patches described above.

evant
27 Oct 2009, 4:58 AM
@prometheus Possibly, but it presents some challenges.

Anyway, from the initial report, this isn't a bug, so I'm going to mark this one as closed.

tonedeaf
6 Apr 2010, 8:26 AM
@Condor: Thanks for the patch!
Complete patch for ExtJS 3.2, note the Store insert() function also needs to be overridden:



/* Paging toolbar enhancements:*/
Ext.override(Ext.data.Store, {
add : function(records){
records = [].concat(records);
if(records.length < 1){
return;
}
for(var i = 0, len = records.length; i < len; i++){
records[i].join(this);
}
var index = this.data.length;
this.data.addAll(records);
if(this.snapshot){
this.snapshot.addAll(records);
}
this.totalLength += records.length;
this.fireEvent('add', this, records, index);
},

insert : function(index, records) {
records = [].concat(records);
for(var i = 0, len = records.length; i < len; i++){
this.data.insert(index, records[i]);
records[i].join(this);
}
if(this.snapshot){
this.snapshot.addAll(records);
}
this.totalLength += records.length;
this.fireEvent('add', this, records, index);
},

remove : function(record){
if(Ext.isArray(record)){
Ext.each(record, function(r){
this.remove(r);
}, this);
}
var index = this.data.indexOf(record);
if(index > -1){
record.join(null);
this.data.removeAt(index);
this.totalLength--;
}
if(this.pruneModifiedRecords){
this.modified.remove(record);
}
if(this.snapshot){
this.snapshot.remove(record);
}
if(index > -1){
this.fireEvent('remove', this, record, index);
}
},


removeAll : function(silent){
var items = [];
this.each(function(rec){
items.push(rec);
});
this.clearData();
this.totalLength = 0;
if(this.snapshot){
this.snapshot.clear();
}
if(this.pruneModifiedRecords){
this.modified = [];
}
if (silent !== true) { // <-- prevents write-actions when we just want to clear a store.
this.fireEvent('clear', this, items);
}
}
});

Ext.override(Ext.PagingToolbar, {
bindStore : function(store, initial){
var doLoad;
if(!initial && this.store){
if(store !== this.store && this.store.autoDestroy){
this.store.destroy();
}else{
this.store.un('beforeload', this.beforeLoad, this);
this.store.un('load', this.onLoad, this);
this.store.un('exception', this.onLoadError, this);
this.store.un('datachanged', this.onChange, this);
this.store.un('add', this.onChange, this);
this.store.un('remove', this.onChange, this);
this.store.un('clear', this.onClear, this);
}
if(!store){
this.store = null;
}
}
if(store){
store = Ext.StoreMgr.lookup(store);
store.on({
scope: this,
beforeload: this.beforeLoad,
load: this.onLoad,
exception: this.onLoadError,
datachanged: this.onChange,
add: this.onChange,
remove: this.onChange,
clear: this.onClear
});
doLoad = true;
}
this.store = store;
if(doLoad){
this.onLoad(store, null, {});
}
},
onLoad : function(store, r, o){
if(!this.rendered){
this.dsLoaded = [store, r, o];
return;
}
var p = this.getParams();
this.cursor = (o.params && o.params[p.start]) ? o.params[p.start] : 0;
var d = this.getPageData(), ap = d.activePage, ps = d.pages;
this.onChange();
},
onChange : function() {
if(this.rendered){
var d = this.getPageData(), ap = d.activePage, ps = d.pages;
this.afterTextItem.setText(String.format(this.afterPageText, d.pages));
this.inputItem.setValue(ap);
this.first.setDisabled(ap == 1);
this.prev.setDisabled(ap == 1);
this.next.setDisabled(ap == ps);
this.last.setDisabled(ap == ps);
this.refresh.enable();
this.updateInfo();
}
this.fireEvent('change', this, d);
},
onClear : function(){
this.cursor = 0;
this.onChange();
}

});

jarlau
1 Jun 2010, 6:55 PM
Say I have 20 items on the first page and I add a new record locally. What should happen? Same with removing a single record on a page of 20, should the server re-request another record from the server?

Hi,
I'm trying to implement the above, add new record(s) to the first page but always keep the first page the same records as 'limit' size, but seems there are some problems with it.


<html>
<head>
<title>Test Grid</title>
<link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css"/>

<!-- GC -->
<!-- LIBS -->
<script type="text/javascript" src="../../adapter/ext/ext-base.js"></script>
<!-- ENDLIBS -->

<script type="text/javascript" src="../../ext-all.js"></script>

<style type="text/css">
html, body {
font: normal 12px verdana;
margin: 0;
padding: 0;
border: 0 none;
}
</style>
<script type="text/javascript">
Ext.ns('Ext.grid.plugins');
Ext.grid.plugins.FixedRowNo = Ext.extend(Object, {
init: function(grid){
this.grid = grid;
grid.store.on('add', this.trimRow, this);
},
trimRow: function(store){
var showStore = function(s) {
for (var i = 0; i < s.getCount(); i++) {
var r = s.getAt(i);
console.log((i+1), r.get('company'));
};
}
showStore(store);
var max = this.grid.maxRow;//store.lastOptions.params.limit;
if (max) {
var count = store.getCount();
if (count > max) {
for (var i = count; i > max; i--) {
//store.removeAt(i-1);
var record = store.getAt(i-1);
store.remove(record);
console.log("removed=",record);
}
}
}
showStore(store);
}
});
Ext.preg('fixedrowno', Ext.grid.plugins.FixedRowNo);

Ext.onReady(function() {
var myData = [
['3m Co',71.72,0.02,0.03,'9/1 12:00am'],
['Alcoa Inc',29.01,0.42,1.47,'9/1 12:00am'],
['Altria Group Inc',83.81,0.28,0.34,'9/1 12:00am'],
['American Express Company',52.55,0.01,0.02,'9/1 12:00am'],
['American International Group, Inc.',64.13,0.31,0.49,'9/1 12:00am'],
['AT&T Inc.',31.61,-0.48,-1.54,'9/1 12:00am'],
];

/**
* Custom function used for column renderer
* @param {Object} val
*/
function change(val){
if(val > 0){
return '<span style="color:green;">' + val + '</span>';
}else if(val < 0){
return '<span style="color:red;">' + val + '</span>';
}
return val;
}

/**
* Custom function used for column renderer
* @param {Object} val
*/
function pctChange(val){
if(val > 0){
return '<span style="color:green;">' + val + '%</span>';
}else if(val < 0){
return '<span style="color:red;">' + val + '%</span>';
}
return val;
}

// create the data store
var store = new Ext.data.ArrayStore({
fields: [
{name: 'company'},
{name: 'price', type: 'float'},
{name: 'change', type: 'float'},
{name: 'pctChange', type: 'float'},
{name: 'lastChange', type: 'date', dateFormat: 'n/j h:ia'}
]
});

// manually load local data
store.loadData(myData);

// create the Grid
var grid = new Ext.grid.GridPanel({
store: store,
plugins: ['fixedrowno'],
tbar: [{
text: 'add',
handler: function() {
// access the Record constructor through the grid's store
var p = new store.recordType({company: 'Wal-Mart Stores, Inc.', price: 45.45, change: 0.73, pctChange: 1.63, lastChange: new Date()});
store.insert(0, p);
}
}, {
text: 'remove',
handler: function() {
store.removeAt(store.getCount()-1);
}
}],
columns: [
new Ext.grid.RowNumberer(),
{id:'company',header: 'Company', width: 160, sortable: true, dataIndex: 'company'},
{header: 'Price', width: 75, sortable: true, renderer: 'usMoney', dataIndex: 'price'},
{header: 'Change', width: 75, sortable: true, renderer: change, dataIndex: 'change'},
{header: '% Change', width: 75, sortable: true, renderer: pctChange, dataIndex: 'pctChange'},
{header: 'Last Updated', width: 85, sortable: true, renderer: Ext.util.Format.dateRenderer('m/d/Y'), dataIndex: 'lastChange'}
],
stripeRows: true,
autoExpandColumn: 'company',
height: 250,
width: 600,
title: 'Array Grid',
maxRow: myData.length,
// config options for stateful behavior
stateful: true,
stateId: 'grid'
});

// render the grid to the specified div in the page
grid.render('grid-example');
});
</script>
</head>
<body>
<div id="grid-example"></div>
</body>
</html>


The drop-in example add record and the plugin will remove the last old record after 'add' event, after the event fired, I found that the store really removed the last record, but the last record is still on the screen. is it a bug?
Thank you.

samir_ware
28 Feb 2013, 12:35 AM
Hey guys
I am doing store reload for grid based on some external events. However this fix is not working with store reload. Can anyone please help me out on this ?
Thanks
Samir