Angular ui-select фильтрует только одно поле

СИТУАЦИЯ:

У меня есть приложение angular, используя angular ui-select для поиска и выбора людей из базы данных.

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

Используя обычный фильтр angular, я могу фильтровать только один из них. Если я попытаюсь отфильтровать оба поля, это больше не работает.


РАБОЧИЙ ПРИМЕР С ОДНИМ ПОЛЕ:

 <ui-select multiple ng-model="database_people.selectedPeople" theme="select2" ng-disabled="disabled" style="width:100%">

    <ui-select-match placeholder="Select person...">{{$item.name}} &lt; {{$item.email}} &gt;</ui-select-match>

    <ui-select-choices repeat="person2 in list_people | filter: {name: $select.search, db_data_type_id: 5}">

            <div ng-bind-html="person2.name | highlight: $select.search"></div>

                <small>
                    email: <span ng-bind-html="''+person2.email | highlight: $select.search"></span>
               </small>

    </ui-select-choices>

 </ui-select>


НЕ РАБОЧИЙ ПРИМЕР С ДВУМ ПОЛЯМИ ФИЛЬТРА:

 <ui-select multiple ng-model="database_people.selectedPeople" theme="select2" ng-disabled="disabled" style="width:100%">

    <ui-select-match placeholder="Select person...">{{$item.name}} &lt; {{$item.email}} &gt;</ui-select-match>

    <ui-select-choices repeat="person2 in list_people | filter: {name: $select.search, email: $select.search, db_data_type_id: 5}">

            <div ng-bind-html="person2.name | highlight: $select.search"></div>

                <small>
                    email: <span ng-bind-html="''+person2.email | highlight: $select.search"></span>
               </small>

    </ui-select-choices>

 </ui-select>

Странно то, что он действительно работает, но только для первого персонажа. Когда я набираю первый символ, он выделяет его в обоих полях, имени и электронной почте. Но когда я набираю второго символа, он больше не работает (В консоли не было ошибок).


ATTEMP ИСПОЛЬЗОВАНИЕ PROPSFILTER FROM angular ОБРАЗЦЫ:

 <ui-select multiple ng-model="database_people.selectedPeople" theme="select2" ng-disabled="disabled" style="width:100%">

    <ui-select-match placeholder="Select person...">{{$item.name}} &lt; {{$item.email}} &gt;</ui-select-match>

    <ui-select-choices repeat="person2 in list_people | propsFilter: {name: $select.search, email: $select.search, db_data_type_id: 5}">

            <div ng-bind-html="person2.name | highlight: $select.search"></div>

                <small>
                    email: <span ng-bind-html="''+person2.email | highlight: $select.search"></span>
               </small>

    </ui-select-choices>

 </ui-select>

В этом случае он полностью сломался, больше нет данных в select2, и я получаю некоторые ошибки в консоли:

Cannot read property 'toString' of null

Cannot read property 'length' of undefined


ВОПРОС (S):

Как фильтровать между полями mulitple? Могу ли я это сделать с помощью обычного фильтра? Или я должен использовать собственный фильтр? Но в этом случае почему не работает должным образом?

Большое спасибо!

Ответ 1

Возможно, потому что одно и то же значение ($ select.search) используется для обоих фильтров электронной почты и имени.

<ui-select-choices repeat="person2 in list_people | filter: {name: $select.search, email: $select.search, db_data_type_id: 5}">
...

Это также объясняет, почему он работает только с первым символом.

Для устранения этого параметра используйте отдельные значения для каждого фильтра:

<ui-select-choices repeat="person2 in list_people | filter: {name: $select.search.name, email: $select.search.email, db_data_type_id: 5}">
...

Ответ 2

Вы можете использовать фильтр свойств, как показано ниже

 <ui-select   ng-model="emplyee" theme="bootstrap">
 <ui-select-match placeholder="Select ...">{{$select.selected.firstName+" "+$select.selected.lastName}}</ui-select-match>
 <ui-select-choices repeat="emp in employees | propertyFilter: {firstName:$select.search, lastName:$select.search}">
 <span ng-bind-html="emp.firstName+' '+emp.lastName | highlight: $select.search"></span>
 </ui-select-choices>

Вам нужно будет изменить свойствоFilter, как показано ниже:

.filter('propertyFilter', function($log) {
 return function(items, props) {
    var out = [];
    if (angular.isArray(items)) {
    items.forEach(function(item) {
        var itemMatches = false;
        var keys = Object.keys(props);
        var optionValue = '';
        for (var i = 0; i < keys.length; i++) {
             optionValue = item[keys[i]] ? optionValue + item[keys[i]].toString().toLowerCase().replace(/ /g, '') : '';
        }
        for (var j = 0; j < keys.length; j++) {
            var text = props[keys[j]].toLowerCase().replace(/ /g, '');
            if (optionValue.indexOf(text) !== -1) {
               itemMatches = true;
               break;
            }
        }
        if (itemMatches) {
            out.push(item);
        }
        });
        } else {
            // Let the output be the input untouched
            out = items;
        }

        return out;
    };
})

Поиск может быть выполнен по значению параметров в целом. Например, если в настройках у вас есть "peter parker", вы можете искать "peter", "parker", "peter parker", "peterparker" и даже выполнять поиск с несколькими пробелами между любым персонажем партер-партер.

Ответ 3

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

Здесь моя измененная версия, которая включает поиск объектов. Очевидно, что это будет работать только в том случае, если все ваши таблицы имеют столбец int Deleted (для меня это часть уникального ключа и значение для идентификатора при удалении), и вы передаете его клиенту.

В дальнейшем я планирую изменить далее, чтобы разрешить рекурсивный поиск объектов.

App.filter('dropdownFilter', function () {
    return function (items, props: Object, keyvalue?) {
    var out = [];

        if (angular.isArray(items)) {
            items.forEach(function (item) {
                var itemMatches = false;
                var canbreak = false;

                // Filter out logically deleted records
                if (item.Deleted != 0)
                    itemMatches = false;
                else {
                    var keys = Object.keys(props);

                    for (var i = 0; i < keys.length; i++) {
                        var prop: string = keys[i];
                        var text = "";
                        // If an object, e.g. searching deep, such as Project: {ProjectName: $select.search}
                        // Then iterate through the object to find values.  
                        // NOTE: This one searches one deep from each object,
                        // e.g. Project.ProjectName
                        //      Project.User.LastName WILL NOT WORK.
                        if (angular.isObject(props[prop])) {
                            angular.forEach(props[prop], function (value, key) {
                                text = value.toLowerCase();
                                if (item[prop][key].toLowerCase().indexOf(text) !== -1) {
                                    itemMatches = true;
                                    canbreak = true;
                                }
                            });
                            if (canbreak)
                                break;
                        }
                        // If it a simple array, then woo!
                        else {
                            text = props[prop].toLowerCase();
                            if (item[prop] != undefined && item[prop].toString().toLowerCase().indexOf(text) !== -1) {
                                itemMatches = true;
                                break;
                            }
                        }
                    }
                }

                if (itemMatches) {
                    out.push(item);
                }
            });
        }
        else {
            // Let the output be the input untouched
            out = items;
        }

    return out;
    }
});

и образец его в использовании (с помощью select2 для angular). Это выпадающее государство/страна со страной как под-объект состояния.

<ui-select ng-model="personneladdress.StateID" theme="select2" class="select2">
    <ui-select-match placeholder="{{language.State}}">{{$select.selected.StateName}}</ui-select-match>
    <ui-select-choices repeat="item.StateID as item in State | dropdownFilter: {StateName: $select.search, Country: {CountryName: $select.search}}">
        <span ng-bind-html="item.StateName | highlight: $select.search"></span><br />
        <small>
            <span ng-bind-html="''+item.Country.CountryName | highlight: $select.search"></span>
        </small>
    </ui-select-choices>
</ui-select>