web-dev-qa-db-fra.com

Filtre strict AngularJS sur un seul champ

J'ai un formulaire avec plusieurs filtres mais pour certains, j'ai besoin d'une comparaison stricte.

tl; dr : comparaison stricte pour user_id pas pour firstname.

<select ng-model="search.user_id">
    <option value="1">1</option>
    <option value="2">2</option>
    <option value="10">10</option>
    <option value="11">11</option>
    <option value="23">23</option>
</select>

<input type="text" ng-model="search.firstname">

<ul>
    <li ng-repeat="user in users | filter:search">#{{ user.user_id }} {{ user.firstname}}</li>
</ul>

J'ai essayé le troisième paramètre true mais cela fonctionne également pour le filtre firstname.

Le problème est le suivant: si vous sélectionnez la valeur 2, tous les utilisateurs ayant un 2 dans leur identifiant seront filtrés, je ne souhaite pas ce comportement.

Voici le violon .

12
Syl

j'ai essayé de le réparer en natif, plutôt qu'avec des filtres personnalisés, cela fonctionne, voici le PLUNKER LINK

dû spécifier plusieurs filtres

<li ng-repeat="user in users | filter:{'user_id':  search.user_id}: true | filter: {'firstname' : search.firstname}">

bien qu'il y ait peu de mises en garde:

  1. je devais changer le type de numéro en chaîne ... 

  2. si je réinitialise la valeur de correspondance exacte cela ne fonctionne pas ...

donc je devais écrire un fichier personnalisé qui fonctionne pour une correspondance exacte et ignore les valeurs vides/nulles

$scope.filter2 = function(field1, field2) {
  if(field2 === "" || field2 === null) return true;
  return field1 === field2;
};

vous les trouverez tous les deux dans le lien fourni

15
harishr

J'ai rencontré ce problème lorsque j'ai chargé une configuration de formulaire à partir de Json et que les numéros ont été passés sous la forme numéro pas chaîne. 

<div ng-repeat="selectedComponent from ctrl.drivers.components |
     filter:{
             manufacturer: component.manufacturer, 
             type: component.type}:true">

Quand j'avais un type de composant de 1 et 10, les deux apparaissaient dans mon répétition avant d'ajouter le :true à mon filtre, et rien quand j'avais ajouté une égalité stricte.

Pour résoudre ce problème, j'ai ajouté une méthode à mon contrôleur appelée castToInt.

ctrl.castToInt = function(value){
    return parseInt(value);
};

Puis j'ai modifié mon filtre pour montrer 

<div ng-repeat="selectedComponent from ctrl.drivers.components |
     filter:{
             manufacturer: component.manufacturer, 
             type: ctrl.castToInt(component.type)}:true">

Voila alors tout a fonctionné

Mon hypothèse est que :true applique une égalité stricte === afin que vous obteniez un faux si vous comparez différents types.

Si vous pouvez accepter de modifier le type de votre valeur, la réponse acceptée est suffisante, mais si vous n'avez aucun contrôle sur les données qui vous sont présentées, cette méthode fonctionne.

- Thomas

1
tFlolo

Comme je ne peux pas commenter les réponses des autres, je le ferai de cette façon.

J'ai utilisé la solution HarisR, mais je l'ai modifiée pour qu'elle puisse être utilisée avec des nombres, même si vous avez besoin de votre valeur en tant que nombre.

$scope.filter2 = function(field1, field2) {
  if(field2 === "" || field2 === null) return true;
  return field1.toString() === field2;
};

ou 

$scope.filter2 = function(field1, field2) {
  if(field2 === "" || field2 === null) return true;
  return ""+field1 === field2;
};
1

Vous pourriez avoir une fonction comme celle-ci dans votre contrôleur

$scope.identical = function(actual, expected){
    return actual === parseInt(expected);
}

et alors vous pourriez l'utiliser comme ça

<li ng-repeat="user in users | filter:search.user_id:identical">
1
Edminsson

Changer dans votre html:

<li ng-repeat="user in users | filter:f">#{{ user.user_id }} {{ user.firstname}}</li>

Je suppose que vous voulez and si les deux valeurs sont présentes. Changez-le en or si vous en avez besoin. Fonction de filtre personnalisé:

$scope.f = function(val) {
    var hasUserId = $scope.search.user_id;
    var hasName = $scope.search.firstname;

    var firstNameMatch = function() { return val.firstname.indexOf($scope.search.firstname) > -1 };
    var userIdMatch = function() { return $scope.search.user_id == val.user_id };

    if(hasUserId && hasName) {
       return  firstNameMatch() && userIdMatch()
    } else if (hasUserId) {
        return userIdMatch();
    } else if (hasName) {
        return firstNameMatch();
    }
    return true;
};

Un changement de plus à votre contrôleur:

$scope.search= {};

Violon fourchu.

0
Andy Gaskell

Si vous souhaitez rechercher par nom, par exemple, ajoutez simplement une zone de texte avec le nom = search.votreNomFieldToName, si vous souhaitez effectuer une recherche dans tous les champs, créez simplement une zone de texte avec search. $, Puis ajoutez simplement filter: search: strict sur votre ng-repeat directif.

Exemple de code Pour mieux expliquer:

<div class="customers view">
<div class="container">
    <header>
        <h3>Customers</h3>
    </header>
    <div class="row">
        <div class="span3">
            Search All:
            <input data-ng-model="search.$" type="text" placeholder="All Search" />
        </div>
        <div class="span3">
            Search By Name: 
            <input data-ng-model="search.firstName" type="text" placeholder="First Name Search" />
        </div>
        <div class="span3">
            Search By LastName:
            <input data-ng-model="search.lastName" type="text" placeholder="Last Name Search" />                
        </div>
        <div class="span3">
            Search By City:
            <input data-ng-model="search.city" type="text" placeholder="City Search" />
        </div>

    </div>
    <div>
        <div class="row cardContainer">
            <div class="span3 card" data-ng-repeat="customer in customers | filter:search:strict | orderBy:'firstName'">
                <button class="btn close cardClose" data-ng-click="deleteCustomer(customer.id)">&times;</button>
                <div class="cardHeader">{{customer.firstName + ' ' + customer.lastName}}</div>
                <div class="cardBody">{{customer.city}}</div>
                <a href="#/customerorders/{{customer.id}}" class="cardBody btn-link">View {{ customer.orders.length }} Orders</a>
            </div>
        </div>
    </div>
</div>