I am working on a Search-As-You-Type component for Ext.js. It features AND-filtering several words, each chained in an OR-filtering against any properties of the records; subsequently. When I type "Ke Ba" it will filter for "Kevin Bacon" and "Becky Kennedy".
I am loading the initial dataset in remote mode.
What happens is that the Data gets loaded into the store via my REST-Proxy and JSON Reader. Currently I do not "filter" on the server side but return everything and Mock the filterin in the client as if the dataset came filtered from the server. So it seems to the combobox.
Now when I change the search string to "Kre Ba", it will re-load from the REST-API (all data), but the Store will be empty to the combobox as I don't have any records matching "Kre Ba".
Somehow Ext-js decides to reset the value of the combobox and the whole search-string disappears.
Is there a neat way to keep the searchstring even when the store has no matching Items (value-wise) after filtering?!
Here is the Ext.js code I found that resets the value:
onLoad: function(store, records, success) {
var me = this;
if (me.ignoreSelection > 0) {
--me.ignoreSelection;
}
// If not querying using the raw field value, we can set the value now we have data
if (success && !store.lastOptions.rawQuery) {
// Set the value on load
// There's no value.
if (me.value == null) {
// Highlight the first item in the list if autoSelect: true
if (me.store.getCount()) {
me.doAutoSelect();
} else {
// assign whatever empty value we have to prevent change from firing
me.setValue(me.value);
}
} else {
me.setValue(me.value);
}
}
},
During debugging I find that me.store.getCount()
returns false
for the check.
UPDATE:
Here is my Combobox config:
Ext.define('MyApp.view.SearchAsYouTypeCombobox', {
extend: 'Ext.form.field.ComboBox',
alias: 'widget.SearchAsYouTypeCombobox',
fieldLabel: 'Label',
hideLabel: true,
emptyText: 'Search',
hideTrigger: true,
minChars: 3,
initComponent: function() {
var me = this;
Ext.applyIf(me, {
//some templates
});
me.callParent(arguments);
}
});
I am trying to build the component as a Controller where you only need to config a Combobox as View and a Store:
Ext.define('MyApp.controller.SearchAsYouTypeComboboxController', {
extend: 'Ext.app.Controller',
stores: [
'SearchAsYouTypeStore'
],
views: [
'SearchAsYouTypeCombobox'
],
onComboboxBeforeQuery1: function(queryPlan, eOpts) {
var me = this;
//determine tokens
//add filter per token
//One could optimize by not clearing the filter when the query String is only extended (leading or trailing) and not changed.
//consider maybe the tokens
//console.log('beforeQuery');
var comboBox = queryPlan.combo;
var myStore = comboBox.getStore();
var queryString = queryPlan.query;
var prevQueryString = comboBox.lastQuery || '';
var words = Ext.String.splitWords(queryString);
//var filterAllPropertiesFilter = {};
console.log('Query String :' + queryString);
console.log("Words: " + words);
//console.log(Ext.JSON.encode(myStore.storeId));
//myStore.clearFilter(true);
if(!Ext.isEmpty(queryString))
{
var filters = [];
//When query has not been only expanded
if(prevQueryString &&
(queryString.length <= prevQueryString.length ||
queryString.toLowerCase().lastIndexOf(prevQueryString.toLowerCase(), 0) !== 0))
{
//Reload everything new
myStore.remoteFilter = true;
myStore.clearFilter(true); //careful with this, it loads all the data unfiltered!
myStore.remoteFilter = false;
console.log('Creating Filters for each word.');
Ext.Array.each(words,
function(word, index, allWords){
me.currentFilterWord = word;
console.log('NEW FILTER: word:' + word);
var filterAllPropertiesFilter = Ext.create('Ext.util.Filter',
{filterString: word,
filterFn: me.filterAllPropertiesFn});
filters.push(filterAllPropertiesFilter);
});
}
else{
if(!prevQueryString){
myStore.remoteFilter = true;
myStore.clearFilter();
}
myStore.remoteFilter = false;
//only for the last word
me.currentFilterWord = words[words.length-1];
console.log('NEW FILTER: word: ' + me.currentFilterWord);
var filterAllPropertiesFilter = Ext.create('Ext.util.Filter',
{filterString: me.currentFilterWord,
filterFn: me.filterAllPropertiesFn});
filters.push(filterAllPropertiesFilter);
Ext.Array.each(myStore.filters.items,
function(filter, index, allFilters){
myStore.removeFilter(filter, false);
});
//myStore.filter(filterAllPropertiesFilter);
}
myStore.filter(filters);
comboBox.lastQuery = queryString;
//filterBy(filters);
}
else
{
myStore.clearFilter(false);
}
comboBox.expand();
queryPlan.cancel = true;
return queryPlan;
},
filterAllPropertiesFn: function(item) {
// filter magic
},
filterOverride: function(filters, value) {
//changed the filter to subsequently filter
},
init: function(application) {
var me = this;
console.log("init of Controller");
//when more than 1 store then error
console.log("Stores: " + this.stores[0]);
var myStoreName = this.stores[0];
var MyStore = me.getStore(myStoreName);
console.log("MyStore: " + MyStore.storeId);
Ext.override(MyStore,{override: myStoreName,
filter: me.filterOverride});
var myComboBoxName = this.views[0];
var MyComboBox = me.getView(myComboBoxName);
console.log("MyComboName: " + myComboBoxName);
console.log("Data: " + MyStore.data.collect('id'));
MyComboBox.store = MyStore;
Ext.override(MyComboBox, {override: myComboBoxName,
store: MyStore});
console.log("myCombo.store: " + MyComboBox.store.storeId);
this.control({
"combobox": {
beforequery: this.onComboboxBeforeQuery1,
}
});
},
});