我正在为Ext.js开发一个Search-As-You-Type组件。它具有AND过滤几个单词,每个单词都对OR记录的任何属性进行OR过滤;随后。 当我输入“Ke Ba”时,它会过滤“Kevin Bacon”和“Becky Kennedy”。
我正在以远程模式加载初始数据集。
通过我的REST-Proxy和JSON Reader将数据加载到商店中会发生什么。目前我没有在服务器端“过滤”但返回所有内容并在客户端中模拟过滤器,就像数据集从服务器过滤一样。所以它似乎在组合框中。
现在,当我将搜索字符串更改为“Kre Ba”时,它将从REST-API(所有数据)重新加载,但由于我没有任何匹配的记录,因此Store对组合框是空的。 Kre Ba“。
不知何故,Ext-js决定重置组合框的值,整个搜索字符串消失。
即使存储在过滤后没有匹配的项目(按值),是否有一种保持搜索字符串的简洁方法?!
我找到的Ext.js代码重置了值:
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);
}
}
},
在调试过程中,我发现me.store.getCount()
返回false
进行检查。
更新
这是我的Combobox配置:
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);
}
});
我正在尝试将组件构建为Controller,您只需要将Combobox配置为View和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,
}
});
},
});
答案 0 :(得分:0)
我做了一些试验......
似乎可以了解组合框beforequery
方法的这些更改。但不知何故,它不会在第一次局部过滤之后“自动选择”第一场比赛了。
onComboboxBeforeQuery1: function(queryPlan, eOpts) {
var me = this;
var comboBox = queryPlan.combo;
var myStore = comboBox.getStore();
var queryString = queryPlan.query;
var prevQueryString = comboBox.lastQuery || '';
var words = Ext.String.splitWords(queryString);
console.log('Query String :' + queryString);
console.log("Words: " + words);A
if(!Ext.isEmpty(queryString))
{
var filters = [];
//When query string has not just only expanded
if(prevQueryString &&
(queryString.length <= prevQueryString.length ||
queryString.toLowerCase().lastIndexOf(prevQueryString.toLowerCase(), 0) !== 0))
{
//Reload everything new
//myStore.remoteFilter = true;
myStore.clearFilter(false);
//myStore.load();
//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(filters);
comboBox.lastQuery = queryString;
}
else
{
myStore.clearFilter(false);
}
comboBox.expand();
queryPlan.cancel = true;
return queryPlan;
}
答案 1 :(得分:0)
我认为你想做的太多了。如果您正在扩展组合框,为什么不覆盖您需要使用的一个函数?
例如,在我写的一些内容中,我对你的组合框有类似的功能。我在autoLoad上有一个组合商店来获取数据。之后,如果我输入任何内容,它会强制doLocalQuery被触发,因为我有queryMode:'local'。我正在覆盖该功能并替换一个部分:
var me = this,
queryString = queryPlan.query,
picker = me.getPicker();
/**
* @author tjohnston
* added queryPlan to combo so we can use it later
* added query and caseSensitive to picker (boundlist) to use in highlighting
*/
me.queryPlan = queryPlan;
picker.query = queryString;
picker.caseSensitive = me.caseSensitive;
// Create our filter when first needed
if (!me.queryFilter) {
// Create the filter that we will use during typing to filter the Store
me.queryFilter = new Ext.util.Filter({
id: me.id + '-query-filter',
anyMatch: me.anyMatch,
combo: me,
caseSensitive: me.caseSensitive,
root: 'data',
/**
* removed property as we're using filterFn
* added filterFn functionality
*/
/** property: me.displayField, **/
filterFn: function(rec) {
return me.filterFn(me,rec);
}
});
me.store.addFilter(me.queryFilter, false);
}
然后它转而调用2个函数:
/** @public **/
/** config for any instance we create if we want to override. **/
filterTest: function(combo,str,regex,rec) {
return regex.test(rec.data[combo.displayField]);
},
/** @private **/
/** our filter function for **/
filterFn: function(combo,rec) {
var me = this,
queryPlan = combo.queryPlan,
anyMatch = me.anyMatch,
caseSensitive = me.caseSensitive ? '' : 'i',
queryString = anyMatch ? queryPlan.query.split(/\s+/) : '^'+queryPlan.query,
total = queryString.length,
isNoMatch = 0,
isMatch = 0,
i = 0;
/** make sure we filter for each text string in the query **/
Ext.each(queryString, function(str) {
if (str !== '') {
//if (str !== '' && str.length >= combo.minChars) {
var query = new RegExp(str,caseSensitive+'g');
if (combo.filterTest(combo,str,query,rec)) {
isMatch++;
} else {
isNoMatch++;
}
}
});
if (isNoMatch > 0) {
/** we match in OR so if we have one match from any query word, return true **/
if (combo.orMatch == true && isMatch > 0 ) {
return true;
}
return false;
} else {
return true;
}
},