PDA

View Full Version : Ext.ux.toolbar.PagingOptions



arthurakay
19 Apr 2011, 7:09 AM
One of the extensions I always end up building is a PagingToolbar with an additional ComboBox for selecting the page size. I've done this a million times in Ext 3.x - but here's my attempt at building it in 4.x

I'm guessing that there's a few improvements that could be made... so any feedback is certainly welcome!



/**
* @class Ext.ux.toolbar.PagingOptions
* @namespace Ext.ux.toolbar
* @extends Ext.toolbar.Paging
* @constructor
* @param {object} configObj
*/
Ext.define('Ext.ux.toolbar.PagingOptions', {
extend: 'Ext.toolbar.Paging',

getPagingItems: function() {
var me = this,
pagingButtons = me.callParent();

if (!Ext.ModelManager.getModel('PageSize')) {
Ext.define('PageSize', {
extend: 'Ext.data.Model',
fields: [{ name: 'pagesize' , type: 'int'}]
});
}

if (!me.pageSizeOptions) {
me.pageSizeOptions = [
{ pagesize: 10 },
{ pagesize: 25 },
{ pagesize: 50 },
{ pagesize: 100 },
{ pagesize: 250 },
{ pagesize: 500 }
];
}

pagingButtons.push({
xtype: 'combobox',
queryMode: 'local',
triggerAction: 'all',
displayField: 'pagesize',
valueField: 'pagesize',
width: 100,
lazyRender: true,
enableKeyEvents: true,
value: me.pageSize,
forceSelection: me.forceSelection || false,
store: new Ext.data.Store({
model: 'PageSize',
data: me.pageSizeOptions
}),
listeners: {
select: function(thisField, value) {
me.fireEvent('pagesizeselect', value[0].get('pagesize'));
},
keypress: function(thisField, eventObj) {
if (eventObj.getKey() !== eventObj.ENTER) { return false; }
me.fireEvent('pagesizeselect', thisField.getValue());
}
}
});

return pagingButtons;
},

initComponent : function() {
var me = this;

me.callParent();

me.addEvents(
'pagesizeselect'
);
}
});


Updates:
- 5/10/2011: Corrected name of "pagesizeselect" event
- 5/25/2011: Added condition on combo "keypress" to only fire event on ENTER key
- 12/21/2011: Added UX to GitHub
- https://github.com/arthurakay/Ext.ux.toolbar.PagingOptions

AlxH
26 Apr 2011, 1:02 PM
This is a great extension. In 3.x i used the pagesizeplugin in almost every grid.
What I like to see is a config option to set the predefined page sizes and an option to force to use the predefined sizes. E.g. pagesizeValues und forceSelection.

arthurakay
26 Apr 2011, 1:04 PM
I could work that in there... I need to update the code above to reflect changes in the 4.0.0 API anyways. I'll post the updates when I get a chance.

arthurakay
27 Apr 2011, 9:18 AM
I updated my original post to include:
- forceSelection config (defaults to false)
- pageSizeOptions config (JSON array of values)

I also removed the "regModel()" call, as that is deprecated in 4.0.0

mitchellsimoens
28 Apr 2011, 7:30 AM
Here is my version. Basically just extracted the combobox out to it's own function to make it a bit more customizable. Did some other personal code touchups, we all have out own style :D


/**
* @class Ext.ux.toolbar.PagingOptions
* @namespace Ext.ux.toolbar
* @extends Ext.toolbar.Paging
* @constructor
* @param {object} configObj
*/
Ext.define('Ext.ux.toolbar.PagingOptions', {
extend : 'Ext.toolbar.Paging',

getPagingItems: function() {
var me = this,
pagingButtons = me.callParent();

Ext.applyIf(me, {
pageSizeOptions : [
{ pagesize : 10 },
{ pagesize : 25 },
{ pagesize : 50 },
{ pagesize : 100 },
{ pagesize : 250 },
{ pagesize : 500 }
]
});

pagingButtons.push(me.buildComboBox());

return pagingButtons;
},

buildComboBox: function() {
var me = this;

Ext.define('PageSize', {
extend : 'Ext.data.Model',
fields : [
{ name : 'pagesize' , type : 'int'}
]
});

return {
xtype : 'combobox',
queryMode : 'local',
triggerAction : 'all',
displayField : 'pagesize',
valueField : 'pagesize',
width : 100,
lazyRender : true,
enableKeyEvents : true,
value : me.pageSize,
forceSelection : me.forceSelection || false,
store : new Ext.data.Store({
model : 'PageSize',
data : me.pageSizeOptions
}),
listeners : {
select : function(combo, value) {
me.fireEvent('pagesizeselect', value[0].get('pagesize'));
},
keypress : function(combo) {
me.fireEvent('pagesizeselect', combo.getValue());
}
}
};
},

initComponent : function() {
var me = this;

me.callParent();

me.addEvents(
'selectpagesize'
);
}
});

tatacalu
10 May 2011, 6:29 AM
Thank you for this example.

tatacalu
10 May 2011, 6:31 AM
Thank you for this example.
I wanted to ask if there is an error in both of the scripts:


listeners : {
select : function(combo, value) {
me.fireEvent('pagesizeselect', value[0].get('pagesize'));
},
keypress : function(combo) {
me.fireEvent('pagesizeselect', combo.getValue());
}
}

//...


me.addEvents( 'selectpagesize' );


Shouldn't the event names coincide ?

Thanks!

arthurakay
10 May 2011, 6:46 AM
Nice catch... yes that was a typo on my part. :">

I've fixed it in the original example.

tatacalu
10 May 2011, 7:59 AM
Thank you for the reply.

I saw in ExtJS4 Class System that a new construct has been introduced for configuration options management:


config: {
option1: defaultValue1,
option2: defaultValue2
// , ... etc...
}

In conjunction with it I saw that you can use the following syntax:


constructor: function(config) {
//...
this.initConfig(config);
//...
return this;
}

I tried to modify the first script posted on this thread in order to have configuration management via the Ext4 way but failed. Also I saw that the initComponent function was called before the constructor function. Does that have anything to do with the asynchronous nature of the new class system ?

I took my information regarding this subject from http://dev.sencha.com/deploy/ext-4.0.0/docs/guide/class_system.html but AFAIK it is still a work in progress.

Also I tried to call:

this.initConfig(config);
this.callParent();
in either order, in the constructor with no luck, strange JS errors kept popping up in Firebug.

Could you please show me a working example of the script with the aforementioned features ?

Thank you!

AlxH
10 May 2011, 11:57 AM
I'm curious about this, too.
This seems to work:


constructor: function(config) {
this.initConfig(config);
Ext.apply(this,config);
this.callParent(config);
return this;
}

But if I understand the docs correctly, it should work without the "Ext.apply".

tatacalu
10 May 2011, 11:42 PM
That doesn't work for me, the whole toolbar isn't rendered and no JS error message is thrown.

ZaDarkSide
24 May 2011, 4:49 AM
Ext JS 4.0.1

It does show the combobox but changing it has no effect.

Error on grid show:
a.invalidate is not a function

Actually i discovered that the error is caused by incompatibility between Ext.grid.plugin.RowEditing and column locking.

arthurakay
25 May 2011, 7:38 AM
@ZaDarkSide - I haven't tried it with any grid plugins (like editing, locking, etc). I'll look into that if I get a chance. It works fine as is with 4.0.1 - if changing the combo has no effect, it's probably because you haven't defined a listener for the "pagesizeselect" event where you have to build the logic for the functionality you want.

@tatacalu - If you post some code, maybe I can help you debug. I'm guessing your problem is unrelated to the extension itself.

ZaDarkSide
30 May 2011, 1:48 AM
The alert doesn't triggers...here's the code



var pager = Ext.create('Ext.ux.toolbar.PagingOptions', {
pageSize: pagesize,
store: store,
dock: 'bottom',
displayInfo: true,
plugins: [pagerprogress, pagerslider],
listeners: {
pagesizeselect: function(pagesize) {
alert(pagesize);
}
}
});

arthurakay
31 May 2011, 6:20 AM
@zadarkside - does it work when you comment out the line involving the plugins?

ZaDarkSide
2 Jun 2011, 1:04 AM
Nevermind i managed getting it working, the event triggers correctly and works with the plugins.

wiznia
7 Jun 2011, 7:09 AM
I like this solution better, instead of making another plugin based on the paging toolbar, it's a plugin. You can easily add this to any paging toolbar you already have... And since it's a combo you can pass any configuration valid for a combo (forceSelection, listeners, etc).



/**
* Ext.ux.grid.PageSize
*/
Ext.define('Ext.ux.grid.PageSize', {
extend : 'Ext.form.field.ComboBox',
alias : 'plugin.pagesize',
beforeText : 'Show',
afterText : 'rows/page',
mode : 'local',
displayField: 'text',
valueField : 'value',
allowBlank : false,
triggerAction: 'all',
width : 50,
maskRe : /[0-9]/,
/**
* initialize the paging combo after the pagebar is randered
*/
init: function(paging) {
if(this.pageSize) {
paging.store.pageSize = this.pageSize;
this.setValue(this.pageSize);
}
paging.on('afterrender', this.onInitView, this);
},
/**
* create a local store for availabe range of pages
*/
store: new Ext.data.SimpleStore({
fields: ['text', 'value'],
data: [['5', 5], ['10', 10], ['15', 15], ['20', 20], ['25', 25], ['50', 50], ['100', 100], ['200', 200], ['500', 500]]
}),
/**
* assing the select and specialkey events for the combobox
* after the pagebar is rendered.
*/
onInitView: function(paging) {
this.setValue(paging.store.pageSize);
paging.add('-', this.beforeText, this, this.afterText);
this.on('select', this.onPageSizeChanged, paging);
this.on('specialkey', function(combo, e) {
if(13 === e.getKey()) {
this.onPageSizeChanged.call(paging, this);
}
});
},
/**
* refresh the page when the value is changed
*/
onPageSizeChanged: function(combo) {
this.store.pageSize = parseInt(combo.getRawValue(), 10);
this.moveFirst();
}
});
You use it like:


{
xtype: 'pagingtoolbar',
store: "Clients",
dock: 'bottom',
displayInfo: true,
plugins: [{
ptype: "pagesize",
pageSize: 50
}

mkiraly
11 Jun 2011, 10:16 PM
I think before you make doRefresh() , set pager to first page : this.moveFirst()

wiznia
13 Jun 2011, 1:59 AM
You are right, that's better. Updated the code.

choino
21 Dec 2011, 4:57 AM
You forget about queryMode:'local' which causes some problems.

PS:thx

arthurakay
21 Dec 2011, 5:07 AM
You forget about queryMode:'local' which causes some problems.

"queryMode" is set to local because it's a local data set - you could create a paging combo with a remote data source, but I have not done that in this UX.

Allan
21 Dec 2011, 9:59 AM
Hi,

experimenting with this using jsFiddle: http://jsfiddle.net/E8fDN/4/ and it doesn't seem to respond when the page size is changed.

Am I using it correctly or is jsFiddle causing a problem?

Thanks,

Allan

arthurakay
21 Dec 2011, 10:11 AM
@allan - You need to set an event listener on the Ext.ux.toolbar.PagingOptions config for "pagesizeselect". The implementation details are left up to you.



Ext.create('Ext.ux.toolbar.PagingOptions', {
store: store,
displayInfo: true,
displayMsg: 'Displaying topics {0} - {1} of {2}',
emptyMsg: "No topics to display",
listeners: {
pagesizeselect: function(size) {
alert(size);
}
}
})

Ratan
29 Feb 2012, 11:41 AM
listeners : { select : function(combo, value) { me.fireEvent('pagesizeselect', value[0].get('pagesize'));
me.store.pageSize = value[0].get('pagesize'); }, keypress : function(combo) { me.fireEvent('pagesizeselect', combo.getValue()); } }

arthurakay
29 Feb 2012, 11:47 AM
@ratan That can certainly work... but I would suggest you do it in the handler for the "pagesizeselect" event (defined on your instance).

I suggest that in case some other logic (or validation) needs to be applied before the page size is refreshed in the UI.

KajaSheen
8 Mar 2012, 12:09 PM
A small update for the plugin from wiznia, had the problem that I had a pagingbar in the combo values. Problem was, that pageSize itself is a property of the combobox (now). Changed that to uxPageSize, now it works like a breeze.


I like this solution better, instead of making another plugin based on the paging toolbar, it's a plugin. You can easily add this to any paging toolbar you already have... And since it's a combo you can pass any configuration valid for a combo (forceSelection, listeners, etc).



...
init: function(paging) {
if(this.uxPageSize) {
paging.store.pageSize = this.uxPageSize;
this.setValue(this.uxPageSize);
}
paging.on('afterrender', this.onInitView, this);
},
...
You use it like:


{
xtype: 'pagingtoolbar',
store: "Clients",
dock: 'bottom',
displayInfo: true,
plugins: [{
ptype: "pagesize",
uxPageSize: 50
}