Ext.ux.ListPaging, Sencha Touch paging of Dataview Lists
Paging of grids in Ext JS is not quite the same as paging of lists in Sencha Touch. We can't send a large number of records with server requests because we must assume that the user has possibly an expensive (mobile) data contract with his provider. So we have to manage efficiently what we send and how much we send. And only then when server communication is unavoidable.
In this article I will show a sample with the Ext.ux.ListPaging plugin that can be included in the Ext.dataview.List class. We are not going to do anything fancy. A working model that can be a stepping stone for your own demand. To make this sample work no extras are done with styling or extra visuals.
What is required
- A model (Ext.data.Model)
- A store (Ext.data.Store)
- A list (Ext.dataview.List, with disclosure)
Our list pagesize is 3 records in a table of a total of 8 records. That is very small for practice but for this sample it makes a few things easier to show. But I suggest that you don't use pages that load too many records at once either. The standard pagesize of a store is 25 records.
A simple search with a list
We start with an empty panel consisting of a search component and a List component. Initially no records are loaded. In Ext JS you might start with a loaded grid before the user searches anything. But in Touch I don't load anything before user action (cheaper).
Initial view
Initial display, no records are shown (the Status button has nothing to do with our sample)
First records loaded
When "01" is entered it will show 3 records matching the search criteria. As you can see the plugin is now adding the "Weitere Sätze" (more records) to the list. The plugin has a config setting autoPaging that is set to true. Now a swipe up will automatically load more records to the model. You can also tap on "Weitere Sätze" and it will also load the additional records.
Browsing with swipe
After a swipe (upwards) the server call adds one more record and adds it to the records in the store. The paging plugin adds now the text "Keine weitere Sätze" (no more records).
No records found
When something is entered in the search field that would not lead to any results, the plugin's output is not displayed and the List object will show the text that is entered at the config item: emptyText. We will hide the plugins output in the callback routine of the store.load method.
The structure of the List
The following code shows the structure of the Ext.dataview.List extension making class Mobile.view.dataview.Artikel. This file would be Artikel.js in the folder Apps/Mobile/view/dataview/. Change the names to names that correspond with your own application. Replace the comment with your own actual data. As you can see I am using still a bit of Ext JS alike coding. I am still not so used to the config descriptions in Sencha Touch classes.
Ext.define('Mobile.view.dataview.Artikel', {
extend: 'Ext.dataview.List',
alias: 'widget.ArtikelDataView',
alternateClassName: ['ArtikelDataView'],
config: {
onItemDisclosure: true, // show the button at end of record
emptyText: 'Keine Daten gefunden', // shown when nothing found
plugins: [
{
xclass: 'Ext.plugin.ListPaging', // part of Sencha Touch
autoPaging: true, // page on swipe down
loadMoreText : 'Weitere Sätze', // text to show when more records
noMoreRecordsText : 'Keine weitere Sätze' // text when all has shown
}
],
itemTpl: [
'Artikel: {ar\_artikel\_nr}',
'{bezeichnung}'
],
items: [
{
xtype: 'toolbar',
docked: 'top',
items: [
{
xtype: 'searchfield',
placeHolder: 'Suchen',
width: 300,
listeners: {
action: function(searchfield, e) {
var me = searchfield.up('ArtikelDataView');
me.SearchfieldClicked(searchfield, e);
}
}
},
... Status button, not important for sample ...
]
}
],
listeners: {
disclose: function(list, record) {
/* ... here you add some action when the disclose button
of a record is tapped (blue arrow)... */
Ext.Msg.alert(
'Article Tap',
'You tapped on ' + record.get('ar_artikel_nr')
);
}
}
},
/*
At initialization the store is created.
This is not very common, it is preferable to use separate classes
for model and store.
Still this is good place to have extra work done.
*/
initialize: function() {
var me = this;
me.callParent();
/* define the model \*/
Ext.define('ArtikelAuswahl', {
extend: 'Ext.data.Model',
config: {
fields: [
... here the fields config has to be put,
fields must correspond with your template fields ...
]
}
});
/* create the data store */
var store = Ext.create('Ext.data.Store', {
model: 'ArtikelAuswahl',
pageSize: 3, /* change this value based on good practice */
proxy: {
type: 'ajax',
actionMethods: {
read: 'POST'
},
url: .. your url to the server ..,
reader: {
rootProperty: 'records',
totalProperty: 'total',
type: 'json'
},
extraParams: {
.. put here some additional parameter values
that you like to send to the server ..
}
},
autoLoad: false /* no automatic loading */
});
/* bind the store to the dataview */
me.setStore(store);
},
/* Routine for the search */
SearchfieldClicked: function(searchfield, e) {
var me = this;
if (searchfield.getValue() === '')
return false;
var store = me.getStore();
/*
Like Ext JS stores \_extraParams can be used to fixate call parameters
to a store. It works like sticky values to a stores proxy.
params will only keep the values for this one call.
*/
store.getProxy().\_extraParams.search = searchfield.getValue();
store.getProxy().\_extraParams.someparameter = 'Some Value';
store.getProxy().\_extraParams.anotherparameter = 141063;
store.load({
scope: me,
params: {
start: 0,
limit: 3 /* change this value based on good practice */
},
/**
the callback is executed after store is loaded
We need to get rid of the message
that is generated by the paging plugin
Only the List "No records found" message has to be shown
**/
callback: function(records, model, success) {
var me = this;
if (records.length === 0) {
/* get the paging plugin, there is only one, so [0] */
var paging = me.getPlugins()[0];
/*
use the method also used in the plugin
(see paging plugin source in the API documentation)
*/
paging.\_loadMoreCmp.hide();
}
}
});
}
});