web-dev-qa-db-fra.com

Angular ui-select ne filtre qu'un seul champ

LA SITUATION:

J'ai une application angulaire utilisant angular ui-select pour rechercher et sélectionner des personnes dans une base de données.

Cela fonctionne bien, sauf une chose ... L'utilisateur devrait pouvoir filtrer parmi les personnes en utilisant deux critères: nom et adresse électronique.

En utilisant le filtre angulaire normal, je ne peux filtrer qu’un d’entre eux ..__ Si je tente de filtrer les deux champs, cela ne fonctionne plus .

EXEMPLE DE TRAVAIL AVEC UN CHAMP:

 <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>


EXEMPLE DE NON FONCTIONNEMENT AVEC DEUX CHAMPS DANS LE FILTRE:

 <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>

La chose étrange est que cela fonctionne réellement MAIS seulement pour le premier caractère . Lorsque je tape le premier caractère, il le met en surbrillance dans les deux champs, nom et email . (Je n'ai aucune erreur dans la console).


TENTATION À L'AIDE DE PROPSFILTER À PARTIR DE ÉCHANTILLONS ANGULAIRES :

 <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>

Dans ce cas, il est complètement cassé, il n'y a plus de données dans le select2 et je reçois des erreurs dans la console:

Cannot read property 'toString' of null

Cannot read property 'length' of undefined


QUESTIONS):

Comment puis-je filtrer parmi plusieurs champs? Puis-je le faire en utilisant un filtre normal? Ou je dois utiliser un filtre personnalisé? Mais dans ce cas, pourquoi ne fonctionne pas correctement?

Merci beaucoup!

16
FrancescoMussi

C'est peut-être parce que la même valeur ($ select.search) est utilisée à la fois pour les filtres email et nom.

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

Cela expliquera également pourquoi cela ne fonctionne qu'avec le premier caractère.

Utilisez des valeurs distinctes pour chaque filtre pour résoudre ce problème:

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

Vous pouvez utiliser le filtre de propriété comme ci-dessous

 <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>

Vous devrez modifier le propertyFilter comme ci-dessous:

.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;
    };
})

La recherche peut être effectuée sur la valeur des options dans son ensemble. Par exemple, si vous avez «peter parker» dans les options, vous pouvez effectuer une recherche avec «peter», «parker», «peter parker», «peterparker» et même rechercher plusieurs espaces entre tous les personnages de peter parker.

8
kunsingh

J'en ai vu quelques-uns flotter comme la réponse de kunsingh, ce qui m'a permis de résoudre mon problème similaire. Dans mon cas, il s'agissait de rechercher plusieurs objets et dans plusieurs objets, mais j'envoie également au client des enregistrements supprimés de manière logique et les filtre éventuellement dans des listes. Pour les listes déroulantes, je voulais que cela soit toujours supprimé sans avoir à modifier l'API. 

Voici ma version modifiée, qui inclut la recherche sur des objets. Évidemment, cela ne fonctionnera que si toutes vos tables ont une colonne int appelée Deleted (Pour moi, fait partie de la clé unique et est définie sur la valeur d'identité une fois supprimée) et que vous la transmettez au client.

Plus tard, je prévois de modifier davantage pour permettre la recherche récursive d'objets.

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's 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;
    }
});

et un échantillon de celui-ci utilisé (en utilisant select2 pour angular). Il s'agit d'un menu déroulant État/pays avec le pays en tant que sous-objet de l'État.

<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>
1
dbmuller

J'ai résolu ce problème en utilisant ce morceau de code:

<ui-select-choices repeat="person2 in list_people | filter: $select.search" >

Dans ui-select-match, j'utilise deux champs:

<ui-select-match placeholder="select One...">
   {{$item.field1}} - {{$item.field2}}
</ui-select-match>
0
Pasha Gharibi