Thank you for reporting this bug. We will make it our priority to review this report.
  1. #1
    Ext JS Premium Member
    Join Date
    Sep 2009
    Location
    Cambridge
    Posts
    97
    Vote Rating
    0
    markalroberts is on a distinguished road

      0  

    Default [CLOSED]Grid removeAll() and PagingToolbar refreshing

    [CLOSED]Grid removeAll() and PagingToolbar refreshing


    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.

  2. #2
    Sencha - Community Support Team Condor's Avatar
    Join Date
    Mar 2007
    Location
    The Netherlands
    Posts
    24,246
    Vote Rating
    96
    Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of

      0  

    Default


    Yes, I believe this should be qualified as a bug.

    Here's a fix:
    Code:
    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.
    Last edited by Condor; 23 Oct 2009 at 3:56 AM. Reason: Added datachanged event for filtering support

  3. #3
    Ext JS Premium Member
    Join Date
    Sep 2009
    Location
    Cambridge
    Posts
    97
    Vote Rating
    0
    markalroberts is on a distinguished road

      0  

    Default


    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.

  4. #4
    Sencha - Ext JS Dev Team evant's Avatar
    Join Date
    Apr 2007
    Location
    Sydney, Australia
    Posts
    17,067
    Vote Rating
    660
    evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute

      0  

    Default


    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.
    Evan Trimboli
    Sencha Developer
    Twitter - @evantrimboli
    Don't be afraid of the source code!

  5. #5
    Sencha User
    Join Date
    May 2008
    Posts
    73
    Vote Rating
    1
    prometheus is on a distinguished road

      0  

    Default


    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?

  6. #6
    Sencha - Community Support Team Condor's Avatar
    Join Date
    Mar 2007
    Location
    The Netherlands
    Posts
    24,246
    Vote Rating
    96
    Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of Condor has much to be proud of

      0  

    Default


    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.

  7. #7
    Sencha - Ext JS Dev Team evant's Avatar
    Join Date
    Apr 2007
    Location
    Sydney, Australia
    Posts
    17,067
    Vote Rating
    660
    evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute evant has a reputation beyond repute

      0  

    Default


    @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.
    Evan Trimboli
    Sencha Developer
    Twitter - @evantrimboli
    Don't be afraid of the source code!

  8. #8
    Ext User tonedeaf's Avatar
    Join Date
    Dec 2007
    Posts
    137
    Vote Rating
    1
    tonedeaf is on a distinguished road

      0  

    Default


    @Condor: Thanks for the patch!
    Complete patch for ExtJS 3.2, note the Store insert() function also needs to be overridden:

    Code:
    /* 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();
        }
    
    });

  9. #9
    Sencha User
    Join Date
    Apr 2008
    Location
    Hong Kong
    Posts
    171
    Vote Rating
    0
    jarlau is on a distinguished road

      0  

    Default


    Quote Originally Posted by evant View Post
    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.
    Code:
    <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.

  10. #10
    Sencha User
    Join Date
    Mar 2011
    Posts
    33
    Vote Rating
    0
    samir_ware is on a distinguished road

      0  

    Default Does this fix as well work with store.reload ()

    Does this fix as well work with store.reload ()


    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