2013-07-25 1 views
3

Я создаю Combibox SearchAsYouType, привязанный к Магазину. Он оснащен tokenizing вход в слова и сравнить его (пока) от всех свойств объекта:ExtJS Store динамически фильтрует в уже отфильтрованном хранилище

{"id": "id_someid", 
"lastName": "Porker", 
"firstName": "Peter"} 

Я решил создать фильтры на лету, когда ввод изменений COMBOBOX:

Ext.define('MyApp.controller.SearchFilterController', { 
    extend: 'Ext.app.Controller', 

    views: [ 
    'SearchAsYouTypeCombo' 
    ], 

    configureFiltersBeforeQuery: function(queryPlan) { 
    //add filter per word token 

    comboBox = queryPlan.combo; 
    queryString = queryPlan.query; 
    words = queryString.split(/[,\s]+/); 
    myStore = comboBox.getStore(); 

    myStore.clearFilter(false); //I also tried without this line, did not help 

    if(!Ext.isEmpty(queryString)) 
    { 
     //create a filter per word 
     filters = []; 
     Ext.Array.each(words, 
      function(word, index, wordsArray){ 
      console.log('NEW FILTER: word: ' + word); 
      filterAllPropertiesFilter = 
       Ext.create('Ext.util.Filter', 
        { filterFn: function(item){ 
         match = false; 
         Ext.Object.each(item.data, 
         function (property, value){ 
         //match beginning of word 
         match = match || (String(value).toLowerCase().lastIndexOf(word.toLowerCase(), 0) === 0); 
        return !match; //do not check other properties when match is found 
       }); 
       return match; 
      }}); 
      filters.push(filterAllPropertiesFilter); 
      return true; 
     }, 
     this, 
     false); 
     myStore.addFilter(filters); 
    } 
    return true; 
}, 

init: function(application) { 
    this.control({ 
     'SearchAsYouTypeCombo': { 
      beforequery: this.configureFiltersBeforeQuery 
     } 
    }); 
} 

});

EDIT: В моем магазине есть «Кевин Бэкон». Предположим, что ни один из LastNames других лиц в местном магазине не начинается с «Ba», но есть кто-то еще, чье имя FirstName «Barry». Поэтому, когда я набираю поисковый запрос «Ба», я хочу увидеть результаты «Кевин Бэкон» и «Барри Уайт». Это работает.

Но вот то, что я не могу выполнить: Когда я теперь идти о расширении SearchString в «Ба, Ke» Я не хочу код, чтобы interate в отношении всех лиц в моем магазине снова при применении фильтра. Я хочу, чтобы следующий фильтр проверял только два результата слева от предыдущего фильтра. Я вроде бы хочу применить фильтр к другому фильтру.

+0

Чтобы быть немного понятнее. Фильтры на одно слово применяются друг к другу, но при каждом нажатии клавиши первое слово снова фильтруется по всем записям из магазина. – haynzz

+1

А что, если я изменю свой вход от «Ba, Ke» до «Be, Ke»? – rixo

+0

Как и в моем текущем решении, я строю фильтры на основе слов, меняющих слово, может привести к потере фильтра и созданию нового. И пока это не последнее слово, мне нужно будет повторно применить все фильтры. EDIT: Но это воспитывает идею как-то управлять фильтрами на уровне контроллера и отслеживать слова. И, возможно, даже о том, если слово изменилось или просто расширено. Но все же мне не хватает ссылки о том, как применить фильтр к хранилищу только в наборе записей, уже полученных из более раннего фильтра. – haynzz

ответ

2

Вы не сможете выполнить то, что хотите, используя фильтры магазина, потому что эти методы в конечном итоге фильтруют весь набор данных. Поэтому вам нужно применить свой фильтр самостоятельно!

Для этого нам необходимо скопировать код с Ext.data.Store#filter, за исключением части, которая восстанавливает весь набор данных перед фильтрацией.

Это дает нам:

// -- Ensure that our current filter is not stalled ---------------- 

// Clear our filtering if the query string has changed in a way 
// that invalidate the current filtering 
if (
    // previous filter is stalled 
) { 
    myStore.data = myStore.snapshot; 
    delete myStore.snapshot; 
} 

// -- Create your new or updated filter ---------------------------- 

var filter = new Ext.util.Filter({ 
    filterFn: function(record) { 
     // your filtering logic 
    } 
}); 

// -- Apply the filter to the currently filtered data -------------- 

myStore.snapshot = myStore.snapshot || myStore.data.clone(); 

// !!! 
// Here's the essential difference. We filter from the filtered dataset: 
myStore.data = myStore.data.filter(myFilter); 

// Instead of starting again from the unfiltered snapshot like in the original code: 
//me.data = me.snapshot.filter(filters); 

myStore.constructGroups(); 

if (myStore.sorters.length && myStore.sortOnFilter && !myStore.remoteSort) { 
    myStore.sort(); 
} else { 
    // fire datachanged event if it hasn't already been fired by doSort 
    myStore.fireEvent('datachanged', myStore); 
    myStore.fireEvent('refresh', myStore); 
} 

// This line's probably useless since filters haven't actually changed... 
//myStore.fireEvent('filterchange', myStore, myStore.filters.items); 

Как я уже намекал на мой предыдущий комментарий, вы, очевидно, нужен способ, чтобы определить, когда строка запроса изменилась таким образом, что визуализации текущей фильтрации устаревшей. Я добавил фальшивое условие в начале кода, чтобы показать вам, как очистить эту хакерскую фильтрацию, когда это произойдет.

+1

Для большей наглядности вы, вероятно, должны переопределить или расширить «Ext.data.store» и поместить этот код в два метода: «quickFilter» и «cleanQuickFilter». – rixo

+0

Благодарим за решение. Я просто хотел спросить, имеет ли смысл то, что вы предложили в своем комментарии. Я проверю это. – haynzz

+0

Возможно, вам понадобится некоторое время, чтобы найти действительно хорошие имена для методов, так как это создаст новый API, но это определенно определенная логика, которая принадлежит магазину ...Я не тестировал код, поэтому дайте мне знать, если он не работает. – rixo

Смежные вопросы