当存储加载没有结果时,Extjs Combobox会保持重置文本值

时间:2013-07-29 15:43:28

标签: javascript extjs combobox

我正在为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,
        }
    });
},
});

2 个答案:

答案 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;
    }
},