3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * As the number of records increases, the time required for the browser to render them increases. Paging is used to
17 * reduce the amount of data exchanged with the client. Note: if there are more records/rows than can be viewed in the
18 * available screen area, vertical scrollbars will be added.
20 * Paging is typically handled on the server side (see exception below). The client sends parameters to the server side,
21 * which the server needs to interpret and then respond with the appropriate data.
23 * Ext.toolbar.Paging is a specialized toolbar that is bound to a {@link Ext.data.Store} and provides automatic
24 * paging control. This Component {@link Ext.data.Store#load load}s blocks of data into the {@link #store} by passing
25 * parameters used for paging criteria.
27 * {@img Ext.toolbar.Paging/Ext.toolbar.Paging.png Ext.toolbar.Paging component}
29 * Paging Toolbar is typically used as one of the Grid's toolbars:
32 * var itemsPerPage = 2; // set the number of items you want per page
34 * var store = Ext.create('Ext.data.Store', {
37 * fields:['name', 'email', 'phone'],
38 * pageSize: itemsPerPage, // items per page
41 * url: 'pagingstore.js', // url that will load data with respect to start and limit params
45 * totalProperty: 'total'
50 * // specify segment of data you want to load using params
58 * Ext.create('Ext.grid.Panel', {
62 * { header: 'Name', dataIndex: 'name' },
63 * { header: 'Email', dataIndex: 'email', flex: 1 },
64 * { header: 'Phone', dataIndex: 'phone' }
69 * xtype: 'pagingtoolbar',
70 * store: store, // same store GridPanel is using
74 * renderTo: Ext.getBody()
77 * To use paging, pass the paging requirements to the server when the store is first loaded.
81 * // specify params for the first page load if using paging
89 * If using {@link Ext.data.Store#autoLoad store's autoLoad} configuration:
91 * var myStore = Ext.create('Ext.data.Store', {
92 * {@link Ext.data.Store#autoLoad autoLoad}: {start: 0, limit: 25},
96 * The packet sent back from the server would have this form:
101 * "rows": [ // ***Note:** this must be an Array
102 * { "id": 1, "name": "Bill", "occupation": "Gardener" },
103 * { "id": 2, "name": "Ben", "occupation": "Horticulturalist" },
105 * { "id": 25, "name": "Sue", "occupation": "Botanist" }
109 * ## Paging with Local Data
111 * Paging can also be accomplished with local data using extensions:
113 * - [Ext.ux.data.PagingStore][1]
114 * - Paging Memory Proxy (examples/ux/PagingMemoryProxy.js)
116 * [1]: http://sencha.com/forum/showthread.php?t=71532
118 Ext.define('Ext.toolbar.Paging', {
119 extend: 'Ext.toolbar.Toolbar',
120 alias: 'widget.pagingtoolbar',
121 alternateClassName: 'Ext.PagingToolbar',
122 requires: ['Ext.toolbar.TextItem', 'Ext.form.field.Number'],
124 * @cfg {Ext.data.Store} store (required)
125 * The {@link Ext.data.Store} the paging toolbar should use as its data source.
129 * @cfg {Boolean} displayInfo
130 * true to display the displayMsg
135 * @cfg {Boolean} prependButtons
136 * true to insert any configured items _before_ the paging buttons.
138 prependButtons: false,
141 * @cfg {String} displayMsg
142 * The paging status message to display. Note that this string is
143 * formatted using the braced numbers {0}-{2} as tokens that are replaced by the values for start, end and total
144 * respectively. These tokens should be preserved when overriding this string if showing those values is desired.
146 displayMsg : 'Displaying {0} - {1} of {2}',
149 * @cfg {String} emptyMsg
150 * The message to display when no records are found.
152 emptyMsg : 'No data to display',
155 * @cfg {String} beforePageText
156 * The text displayed before the input item.
158 beforePageText : 'Page',
161 * @cfg {String} afterPageText
162 * Customizable piece of the default paging text. Note that this string is formatted using
163 * {0} as a token that is replaced by the number of total pages. This token should be preserved when overriding this
164 * string if showing the total page count is desired.
166 afterPageText : 'of {0}',
169 * @cfg {String} firstText
170 * The quicktip text displayed for the first page button.
171 * **Note**: quick tips must be initialized for the quicktip to show.
173 firstText : 'First Page',
176 * @cfg {String} prevText
177 * The quicktip text displayed for the previous page button.
178 * **Note**: quick tips must be initialized for the quicktip to show.
180 prevText : 'Previous Page',
183 * @cfg {String} nextText
184 * The quicktip text displayed for the next page button.
185 * **Note**: quick tips must be initialized for the quicktip to show.
187 nextText : 'Next Page',
190 * @cfg {String} lastText
191 * The quicktip text displayed for the last page button.
192 * **Note**: quick tips must be initialized for the quicktip to show.
194 lastText : 'Last Page',
197 * @cfg {String} refreshText
198 * The quicktip text displayed for the Refresh button.
199 * **Note**: quick tips must be initialized for the quicktip to show.
201 refreshText : 'Refresh',
204 * @cfg {Number} inputItemWidth
205 * The width in pixels of the input field used to display and change the current page number.
210 * Gets the standard paging items in the toolbar
213 getPagingItems: function() {
218 tooltip: me.firstText,
219 overflowText: me.firstText,
220 iconCls: Ext.baseCSSPrefix + 'tbar-page-first',
222 handler: me.moveFirst,
226 tooltip: me.prevText,
227 overflowText: me.prevText,
228 iconCls: Ext.baseCSSPrefix + 'tbar-page-prev',
230 handler: me.movePrevious,
236 xtype: 'numberfield',
239 cls: Ext.baseCSSPrefix + 'tbar-page-number',
240 allowDecimals: false,
243 enableKeyEvents: true,
246 width: me.inputItemWidth,
250 keydown: me.onPagingKeyDown,
251 blur: me.onPagingBlur
255 itemId: 'afterTextItem',
256 text: Ext.String.format(me.afterPageText, 1)
261 tooltip: me.nextText,
262 overflowText: me.nextText,
263 iconCls: Ext.baseCSSPrefix + 'tbar-page-next',
265 handler: me.moveNext,
269 tooltip: me.lastText,
270 overflowText: me.lastText,
271 iconCls: Ext.baseCSSPrefix + 'tbar-page-last',
273 handler: me.moveLast,
279 tooltip: me.refreshText,
280 overflowText: me.refreshText,
281 iconCls: Ext.baseCSSPrefix + 'tbar-loading',
282 handler: me.doRefresh,
287 initComponent : function(){
289 pagingItems = me.getPagingItems(),
290 userItems = me.items || me.buttons || [];
292 if (me.prependButtons) {
293 me.items = userItems.concat(pagingItems);
295 me.items = pagingItems.concat(userItems);
299 if (me.displayInfo) {
301 me.items.push({xtype: 'tbtext', itemId: 'displayItem'});
309 * Fires after the active page has been changed.
310 * @param {Ext.toolbar.Paging} this
311 * @param {Object} pageData An object that has these properties:
315 * The total number of records in the dataset as returned by the server
317 * - `currentPage` : Number
319 * The current page number
321 * - `pageCount` : Number
323 * The total number of pages (calculated from the total number of records in the dataset as returned by the
324 * server and the current {@link Ext.data.Store#pageSize pageSize})
326 * - `toRecord` : Number
328 * The starting record index for the current page
330 * - `fromRecord` : Number
332 * The ending record index for the current page
337 * @event beforechange
338 * Fires just before the active page is changed. Return false to prevent the active page from being changed.
339 * @param {Ext.toolbar.Paging} this
340 * @param {Number} page The page number that will be loaded on change
344 me.on('afterlayout', me.onLoad, me, {single: true});
346 me.bindStore(me.store || 'ext-empty-store', true);
349 updateInfo : function(){
351 displayItem = me.child('#displayItem'),
353 pageData = me.getPageData(),
357 count = store.getCount();
361 msg = Ext.String.format(
368 displayItem.setText(msg);
369 me.doComponentLayout();
385 pageData = me.getPageData();
386 currPage = pageData.currentPage;
387 pageCount = pageData.pageCount;
388 afterText = Ext.String.format(me.afterPageText, isNaN(pageCount) ? 1 : pageCount);
390 me.child('#afterTextItem').setText(afterText);
391 me.child('#inputItem').setValue(currPage);
392 me.child('#first').setDisabled(currPage === 1);
393 me.child('#prev').setDisabled(currPage === 1);
394 me.child('#next').setDisabled(currPage === pageCount);
395 me.child('#last').setDisabled(currPage === pageCount);
396 me.child('#refresh').enable();
398 me.fireEvent('change', me, pageData);
402 getPageData : function(){
403 var store = this.store,
404 totalCount = store.getTotalCount();
408 currentPage : store.currentPage,
409 pageCount: Math.ceil(totalCount / store.pageSize),
410 fromRecord: ((store.currentPage - 1) * store.pageSize) + 1,
411 toRecord: Math.min(store.currentPage * store.pageSize, totalCount)
417 onLoadError : function(){
418 if (!this.rendered) {
421 this.child('#refresh').enable();
425 readPageFromInput : function(pageData){
426 var v = this.child('#inputItem').getValue(),
427 pageNum = parseInt(v, 10);
429 if (!v || isNaN(pageNum)) {
430 this.child('#inputItem').setValue(pageData.currentPage);
436 onPagingFocus : function(){
437 this.child('#inputItem').select();
441 onPagingBlur : function(e){
442 var curPage = this.getPageData().currentPage;
443 this.child('#inputItem').setValue(curPage);
447 onPagingKeyDown : function(field, e){
450 pageData = me.getPageData(),
451 increment = e.shiftKey ? 10 : 1,
456 pageNum = me.readPageFromInput(pageData);
457 if (pageNum !== false) {
458 pageNum = Math.min(Math.max(1, pageNum), pageData.pageCount);
459 if(me.fireEvent('beforechange', me, pageNum) !== false){
460 me.store.loadPage(pageNum);
463 } else if (k == e.HOME || k == e.END) {
465 pageNum = k == e.HOME ? 1 : pageData.pageCount;
466 field.setValue(pageNum);
467 } else if (k == e.UP || k == e.PAGEUP || k == e.DOWN || k == e.PAGEDOWN) {
469 pageNum = me.readPageFromInput(pageData);
471 if (k == e.DOWN || k == e.PAGEDOWN) {
474 pageNum += increment;
475 if (pageNum >= 1 && pageNum <= pageData.pages) {
476 field.setValue(pageNum);
483 beforeLoad : function(){
484 if(this.rendered && this.refresh){
485 this.refresh.disable();
490 doLoad : function(start){
491 if(this.fireEvent('beforechange', this, o) !== false){
497 * Move to the first page, has the same effect as clicking the 'first' button.
499 moveFirst : function(){
500 if (this.fireEvent('beforechange', this, 1) !== false){
501 this.store.loadPage(1);
506 * Move to the previous page, has the same effect as clicking the 'previous' button.
508 movePrevious : function(){
510 prev = me.store.currentPage - 1;
513 if (me.fireEvent('beforechange', me, prev) !== false) {
514 me.store.previousPage();
520 * Move to the next page, has the same effect as clicking the 'next' button.
522 moveNext : function(){
524 total = me.getPageData().pageCount,
525 next = me.store.currentPage + 1;
528 if (me.fireEvent('beforechange', me, next) !== false) {
535 * Move to the last page, has the same effect as clicking the 'last' button.
537 moveLast : function(){
539 last = me.getPageData().pageCount;
541 if (me.fireEvent('beforechange', me, last) !== false) {
542 me.store.loadPage(last);
547 * Refresh the current page, has the same effect as clicking the 'refresh' button.
549 doRefresh : function(){
551 current = me.store.currentPage;
553 if (me.fireEvent('beforechange', me, current) !== false) {
554 me.store.loadPage(current);
559 * Binds the paging toolbar to the specified {@link Ext.data.Store}
560 * @param {Ext.data.Store} store The store to bind to this toolbar
561 * @param {Boolean} initial (Optional) true to not remove listeners
563 bindStore : function(store, initial){
566 if (!initial && me.store) {
567 if(store !== me.store && me.store.autoDestroy){
568 me.store.destroyStore();
570 me.store.un('beforeload', me.beforeLoad, me);
571 me.store.un('load', me.onLoad, me);
572 me.store.un('exception', me.onLoadError, me);
579 store = Ext.data.StoreManager.lookup(store);
582 beforeload: me.beforeLoad,
584 exception: me.onLoadError
591 * Unbinds the paging toolbar from the specified {@link Ext.data.Store} **(deprecated)**
592 * @param {Ext.data.Store} store The data store to unbind
594 unbind : function(store){
595 this.bindStore(null);
599 * Binds the paging toolbar to the specified {@link Ext.data.Store} **(deprecated)**
600 * @param {Ext.data.Store} store The data store to bind
602 bind : function(store){
603 this.bindStore(store);
607 onDestroy : function(){
608 this.bindStore(null);