Background
In general, the page display is the front-end is only responsible for the display, the background through the SQL statement to achieve paged query. When the total data volume is below thousands, it is suitable to query all the eligible data at once, so that the front page is responsible for paging is also a choice.
Instance
Paging is now implemented through the ExtJS 4 extension class library Ext.ux.data.PagingStore, which is recommended to get the latest version on GitHub before use.
It is very simple to use, just change the store's inheriting class to "Ext.ux.data.PagingStore", other paging configuration can refer to the previous article "ExtJS Implementation paging grid paging".
Ext.define (' XXX ', {extend: ' Ext.ux.data.PagingStore ' ...})
However, there are 2 more questions for different scenarios:
- How do I force re-querying of background data after local paging?
According to the implementation of Pagingstore, only the query parameters are modified before the background query is called again. However, if we modify a piece of data in the list, we need to refresh the list by the current criteria. At this point, I add a timestamp to the condition to refresh.
Store.getproxy (). Extraparams._time=new Date (). GetTime ();
- How does "refresh" in the paging button get rid of it?
Because it is a local paging, ExtJS's own paging "refresh" button appears to be a device. It can be hidden after the page is loaded. Add the AfterRender event to the controller layer to implement. The code in the tab_id can be found through the developer tools in the ExtJS generated page source code, here is a point, I hope you write better selectors.
Afterrender:function () { ext.get ("tab_id"). Down (". X-tbar-loading"). (". X-btn"). setvisible (false);}
Attach the source code of Ext.ux.data.PagingStore.js:
/** pagingstore for ext 4-v0.6* Based on Ext.ux.data.PagingStore for ext JS 3, by Condor, found at* http://www.sencha.co m/forum/showthread.php?71532-ext.ux.data.pagingstore-v0.5* Stores is configured as normal, with whatever proxies you need For remote or Local. Set the* lastoptions when defining the store to set start, limit and current page. Store should only* request new data if params or extraparams changes. In Ext JS 4, start, limit and page is part of the* options but no longer part of params.* Example remote store:* var Mystore = ext.create (' Ext.ux.data.PagingStore ', {model: ' Artist ', Pagesize:3, Lastoptio NS: {start:0, Limit:3, page:1}, Proxy: {type: ' ajax ', url: ' Url/goes/here ', Reader: {type: ' json ', Root: ' Rows '}}); * Example L Ocal store:* var mystore = ext.create (' Ext.ux.data.PagingStore ', {model: ' ArtiSt ', Pagesize:3, proxy: {type: ' Memory ', reader: {type: ' Arra Y '}}, Data:data}); * To force a reload, delete store.lastparams.*/ext.define (' ext.u X.data.pagingstore ', {extend: ' Ext.data.Store ', alias: ' Store.pagingstore ', destroystore:function () {this.callparent (arguments); this.alldata = null;},/*** Currently, only looking at start, limit, page and params properties of options. Ignore everything* else.* @param {Ext.data.Operation} options* @return {boolean}*/ispaging:function (options) {var me = t His,start = Options.start,limit = Options.limit,page = Options.page,currentparams;if ((typeof start! = ' number ') | | (typeof limit! = ' number ')) {Delete Me.start;delete Me.limit;delete me.page;me.lastparams = Options.params;return false;} Me.start = Start;me.limit = Limit;me.currentpage = Page;var Lastparams = This.lastparams;currentparams = Ext.apply ({}, opt Ions.params, This.proxy? This.proxy.exTraparams: {}); me.lastparams = Currentparams;if (!this.proxy) {return true;} No params from a previous load, must is the first loadif (!lastparams) {return false;} Iterate through all of the current parameters, if there is differences, then this is//not just a paging request, but in Stead a true load Requestfor (var param in currentparams) {if (Currentparams.hasownproperty (param) && (Currentpara Ms[param]!== Lastparams[param])) {return false;}} Do the same iteration, but this time walking through the lastparamsfor (param in lastparams) {if (lastparams.hasownprope Rty (param) && (Currentparams[param]!== Lastparams[param]) {return false;}} Return True;},applypaging:function () {var me = This,start = Me.start,limit = Me.limit,alldata, Data;if ((typeof start = = ' Number ') && (typeof limit = = ' number ') {alldata = This.data;data = new Ext.util.MixedCollection (alldata.allowfu Nctions, Alldata.getkey);d Ata.addall (AllData.items.slice (Start, start + limit); Me.alldata = Alldata;me.data = Data;}},loadrecords:function (records, options) {var me = This,i = 0,length = Records.length,start,a Ddrecords,snapshot = Me.snapshot,alldata = me.alldata;if (options) {start = Options.start;addrecords = Options.addrecords;} if (!addrecords) {delete Me.alldata;delete me.snapshot;me.cleardata (true);} else if (alldata) {Alldata.addall (Records) ;} else if (snapshot) {Snapshot.addall (records);} Me.data.addAll (records); if (!me.alldata) {me.applypaging ();} If (start!== undefined) {for (; i < length; i++) {Records[i].index = start + I;records[i].join (Me),}} else {for (; I & Lt Length i++) {records[i].join (Me);}} /** this rather inelegant suspension and resumption of events are required because both the filter and sort functions* fire An additional datachanged event, which are not wanted. Ideally we would do this a different. The first* datachanged event is fired by the call to This.add, above.*/me.suspendevents (); if (Me.filteronload &&! Me.remotefilter) {me.filtER ();} if (me.sortonload &&!me.remotesort) {me.sort (undefined, undefined, undefined, true);} Me.resumeevents (); Me.fireevent (' datachanged ', Me); Me.fireevent (' Refresh ', Me);},loaddata:function (data, append) { var me = This,model = Me.model,length = Data.length,newdata = [],i,record;me.ispaging (ext.apply ({}, this.lastOptions? thi S.lastoptions: {}));//make sure each data element was an Ext.data.Model instancefor (i = 0; i < length; i++) {record = Data[i];if (! ( Record.ismodel) {record = Ext.ModelManager.create (record, model);} Newdata.push (record);} Me.loadrecords (NewData, append me.addRecordsOptions:undefined);},loadrawdata:function (data, append) {var me = This,r Esult = Me.proxy.reader.read (data), records = Result.records;if (result.success) {me.totalcount = Result.total; Me.ispaging (Ext.apply ({}, This.lastoptions this.lastoptions: {})); Me.loadrecords (records, append?) me.addRecordsOptions:undefined); me.fireevent (' Load ', Me, records, true);}},load:function (options) {VAr me = this,pagingoptions;options = Options | | {};if (typeof options = = ' function ') {options = {callback:options};} Options.groupers = Options.groupers | | Me.groupers.items;options.page = Options.page | | Me.currentpage;options.start = (options.start!== undefined)? Options.start: (options.page-1) * me.pagesize;options.limit = Options.limit | | Me.pagesize;options.addrecords = Options.addrecords | | False;if (me.buffered) {return me.loadtoprefetch (options);} var operation;options = ext.apply ({action: ' read ', Filters:me.filters.items,sorters:me.getsorters ()}, options); Me.lastoptions = Options;operation = new Ext.data.Operation (options), if (Me.fireevent (' Beforeload ', Me, operation)!== False) {me.loading = True;pagingoptions = Ext.apply ({}, Options), if (me.ispaging (pagingoptions)) {Ext.Function.defer ( function () {if (me.alldata) {me.data = Me.alldata;delete me.alldata;} Me.applypaging (); Me.fireevent ("datachanged", Me); Me.fireevent (' Refresh ', me); var r = [].concat (me.data.items); Me.loading = false;me.fireevent ("Load", ME, R, True); if (Me.hasListeners.read) {me.fireevent (' read ', ME, R, true);} if (options.callback) {options.callback.call (Options.scope | | me, R, Options, True);}}, 1, me); return me; Me.proxy.read (operation, Me.onproxyload, ME);} Return Me;},insert:function (index, records) {var me = This,sync = False,i,record,len;records = [].concat (records); for (i = 0, len = records.length; i < Len; i++) {record = Me.createmodel (Records[i]); Record.set (me.modeldefaults);//Reassign the model in the array in case it wasn ' T created yetrecords[i] = Record;me.data.insert (index + i, record); Record.join (me); sync = Sync | | Record.phantom = = = true;} if (me.alldata) {me.allData.addAll (records);} if (me.snapshot) {me.snapshot.addAll (records);} if (me.requiresort) {//suspend events so the usual data changed events don ' t get Fired.me.suspendEvents (); Me.sort (); me.re Sumeevents ();} Me.fireevent (' Add ', Me, records, index); me.fireevent (' datachanged ', Me); if (Me.autosync && sync &Amp;&!me.autosyncsuspended) {me.sync ();}},dosort:function (SORTERFN) {var me = this,range,ln,i;if (me.remoteSort) { For a buffered Store, we had to clear the prefetch cache since it was keyed by the index within the dataset.//then we Must prefetch the new Page 1, and when this arrives, reload the visible part of the store//via the Guaranteedrange eventi F (me.buffered) {me.pageMap.clear (); Me.loadpage (1);} else {//the load function would pick up the new sorters and request th E sorted data from the Proxyme.load ();}} else {if (me.alldata) {me.data = Me.alldata;delete me.alldata;} Me.data.sortBy (SORTERFN); if (!me.buffered) {range = Me.getrange (); ln = range.length;for (i = 0; i < ln; i++) {range[i]. index = i;}} Me.applypaging (); Me.fireevent (' datachanged ', Me); Me.fireevent (' Refresh ', Me);}},gettotalcount:function () {return This.alldata? This.allData.getCount (): This.totalcount | | 0;},//inherit docsgetnewrecords:function () {if (this.alldata) {return this.allData.filterBy (this.filternew). Items;} Return This.data.filterBy (this.filternew). Items;},//inherit docsgetupdatedrecords:function () {if (this.alldata) { Return This.allData.filterBy (this.filterupdated). Items;} Return This.data.filterBy (this.filterupdated). Items;},remove:function (Records,/* private */Ismove) {if (! Ext.isarray (Records)) {records = [records];} /** Pass The Ismove parameter if we know we ' re going to being re-inserting this record*/ismove = Ismove = = True;var me = Thi S,sync = False,i = 0,length = Records.length,isnotphantom,index,record;for (; i < length; i++) {record = Records[i];ind ex = Me.data.indexOf (record); if (me.alldata) {me.allData.remove (record);} if (me.snapshot) {me.snapshot.remove (record);} if (Index >-1) {Isnotphantom = Record.phantom!== true;//don ' t push Phantom Records onto REMOVEDIF (!ismove && ; Isnotphantom) {//Store the index the record was removed by the RejectChanges can re-insert at the correct place.// The record ' s Index property won ' t does, as that's thE index in the overall dataset if Store is Buffered.record.removedFrom = Index;me.removed.push (record);} Record.unjoin (Me); Me.data.remove (record); sync = Sync | | Isnotphantom;me.fireevent (' Remove ', ME, record, index);}} Me.fireevent (' datachanged ', Me); if (!ismove && me.autosync && sync &&!me.autosyncsuspended) { Me.sync ();}},filter:function (filters, value) {if (ext.isstring (filters)) {filters = {property:filters,value:value};} var me = this,decoded = Me.decodefilters (filters), i = 0,dolocalsort = me.sorters.length && me.sortonfilter &&A MP;!me.remotesort,length = Decoded.length;for (; i < length; i++) {me.filters.replace (decoded[i]);} if (me.remotefilter) {/So, Prefetchpage does not consider the store to being fully loaded if the local count is equal T o The total countdelete me.totalcount;//for a buffered Store, we had to clear the prefetch cache because the dataset wil L Change upon filtering.//then we must prefetch the new Page 1, and whenThat's arrives, reload the visible part of the store//via the Guaranteedrange eventif (me.buffered) {me.pageMap.clear (); me. LoadPage (1);} else {//Reset to the first page, the filter was likely to produce a smaller data Setme.currentpage = 1;//the load function Would pick up the new filters and request the filtered data from the Proxyme.load ();} else {/*** @property {Ext.util.MixedCollection} snapshot* A Pristine (unfiltered) collection of the records in this store. This was used to reinstate* records if a filter is removed or changed*/if (Me.filters.getCount ()) {me.snapshot = Me.snap Shot | | Me.allData.clone () | | Me.data.clone (); if (me.alldata) {me.data = Me.alldata;delete me.alldata;} Me.data = Me.data.filter (Me.filters.items); me.applypaging (); if (Dolocalsort) {me.sort ();} else {//Fire datachanged Event if it hasn ' t already been fired by Dosortme.fireevent (' datachanged ', Me), me.fireevent (' Refresh ', Me),}}}, Clearfilter:function (suppressevent) {var me = this;me.filters.clear (); if (ME.REmotefilter) {//In a buffered Store, the meaing of suppressevent are to simply clear the filters collectionif (suppresseve NT) {return;} So, Prefetchpage does not consider the store to being fully loaded if the local count is equal to the total Countdelet e me.totalcount;//for a buffered Store, we had to clear the prefetch cache because the dataset would change upon Filterin g.//then we must prefetch the new Page 1, and when this arrives, reload the visible part of the store//via the guarantee Drange Eventif (me.buffered) {me.pageMap.clear (); Me.loadpage (1);} else {//Reset to the first page, clearing a filter would Destroy the context of the current datasetme.currentpage = 1;me.load ();}} else if (me.isfiltered ()) {me.data = Me.snapshot.clone ();d elete me.alldata;delete me.snapshot;me.applypaging (); Suppressevent!== True) {me.fireevent (' datachanged ', Me); Me.fireevent (' Refresh ', Me);}}},isfiltered:function () {var Snapshot = This.snapshot;return!! Snapshot && snapshot!== (tHis.alldata | | This.data);},filterby:function (FN, scope) {var me = This;me.snapshot = Me.snapshot | | me.allData.clone () | | me.data.clon E (); me.data = Me.queryby (fn, scope | | me); me.applypaging (); Me.fireevent (' datachanged ', Me); Me.fireevent (' Refresh ', ME );},queryby:function (FN, scope) {var me = This,data = Me.snapshot | | me.alldata | | Me.data;return Data.filterby (FN, SCOP e | | me);},collect:function (Dataindex, Allownull, bypassfilter) {var me = This,data = (Bypassfilter = = True && (me.s Napshot | | Me.alldata))? (Me.snapshot | | me.alldata): Me.data;return data.collect (dataindex, ' data ', allownull);},getbyid:function (ID) {return (This.snapshot | | this.alldata | | this.data). FINDBY (function (record) {return Record.getid () = = = ID;});},removeall: function (silent) {var me = This;me.cleardata (); if (me.snapshot) {me.snapshot.clear ();} if (me.alldata) {me.allData.clear ();} Special handling to synch the Pagemap only for removeall//todo:handle other store/data modifications WRTBuffered Stores.if (Me.pagemap) {me.pageMap.clear ();} if (silent!== true) {me.fireevent (' clear ', Me);}});
ExtJS Remote Data-local paging