The following is my solution for infinite scrolling for combobox, Extjs 4.0
Ext.define('TestProject.testselect', {
extend:'Ext.form.field.ComboBox',
alias: ['widget.testselect'],
requires: ['Ext.selection.Model', 'Ext.data.Store'],
/**
* This will contain scroll position when user reaches the bottom of the list
* and the store begins to upload data
*/
beforeRefreshScrollTop: 0,
/**
* This will be changed to true, when there will be no more records to upload
* to combobox
*/
isStoreEndReached : false,
/**
* The main thing. When creating picker, we add scroll listener on list dom element.
* Also add listener on load mask - after load mask is hidden we set scroll into position
* that it was before new items were loaded to list. This prevents 'jumping' of the scroll.
*/
createPicker: function() {
var me = this,
picker = me.callParent(arguments);
me.mon(picker, {
'render' : function() {
Ext.get(picker.getTargetEl().id).on('scroll', me.onScroll, me);
me.mon(picker.loadMask, {
'hide' : function() {
Ext.get(picker.id + '-listEl').scroll("down", me.beforeRefreshScrollTop, false);
},
scope: me
});
},
scope: me
});
return picker;
},
/**
* Method which is called when user scrolls the list. Checks if the bottom of the
* list is reached. If so - sends 'nextPage' request to store and checks if
* any records were received. If not - then there is no more records to load, and
* from now on if user will reach the bottom of the list, no request will be sent.
*/
onScroll: function(){
var me = this,
parentElement = Ext.get(me.picker.getTargetEl().id),
parentElementTop = parentElement.getScroll().top,
scrollingList = Ext.get(me.picker.id+'-items');
if(scrollingList != undefined) {
if(!me.isStoreEndReached && parentElementTop >= scrollingList.getHeight() - parentElement.getHeight()) {
var multiselectStore = me.getStore(),
beforeRequestCount = multiselectStore.getCount();
me.beforeRefreshScrollTop = parentElementTop;
multiselectStore.nextPage({
params: this.getParams(this.lastQuery),
callback: function() {
me.isStoreEndReached = !(multiselectStore.getCount() - beforeRequestCount > 0);
}
});
}
}
},
/**
* Took this method from Ext.form.field.Picker to collapse only if
* loading finished. This solve problem when user scrolls while large data is loading.
* Whithout this the list will close before finishing update.
*/
collapse: function() {
var me = this;
if(!me.getStore().loading) {
me.callParent(arguments);
}
},
/**
* Reset scroll and current page of the store when loading all profiles again (clicking on trigger)
*/
doRawQuery: function() {
var me = this;
me.beforeRefreshScrollTop = 0;
me.getStore().currentPage = 0;
me.isStoreEndReached = false;
me.callParent(arguments);
}
});
When creating element, should be passed id to the listConfig, also I pass template for list, because I need it to be with id. I didn't find out more elegant way to do this. I appreciate any advice.
{
id: 'testcombo-multiselect',
xtype: 'testselect',
store: Ext.create('TestProject.testStore'),
queryMode: 'remote',
queryParam: 'keyword',
valueField: 'profileToken',
displayField: 'profileToken',
tpl: Ext.create('Ext.XTemplate',
'<ul id="ds-profiles-boundlist-items"><tpl for=".">',
'<li role="option" class="' + Ext.baseCSSPrefix + 'boundlist-item' + '">',
'{profileToken}',
'</li>',
'</tpl></ul>'
),
listConfig: {
id: 'testcombo-boundlist'
}
},
And the store:
Ext.define('TestProject.testStore',{
extend: 'Ext.data.Store',
storeId: 'teststore',
model: 'TestProject.testModel',
pageSize: 13, //the bulk of records to receive after each upload
currentPage: 0, //server side works with page numeration starting with zero
proxy: {
type: 'rest',
url: serverurl,
reader: 'json'
},
clearOnPageLoad: false //to prevent replacing list items with new uploaded items
});