Filtre sur mesure avec AngularJS ngTable

j'essaie de construire une table en utilisant ngTable, mais avec un filtrage personnalisé différent de celui décrit dans l'exemple de la page ngTable.

je veux un filtrage en place, mais je ne veux pas que ngTable affiche les sélecteurs de filtres. Je veux les rendre moi-même (au-dessus du tableau), puis les référencer dans ma méthode "getData ()".

l'exemple mentionné plus haut n'explique pas le fonctionnement de ces machines. Je n'ai aucune idée exactement ce qui doit être spécifié dans la propriété" filter "de chaque élément" td". Je comprends la syntaxe de base de la fonction AngularJS $filter, mais je ne suis pas clair sur ce que ngTable fait avec cela. Dans le premier exemple, il semble que je ne puisse faire que la vérification "égal", qui ne sélectionnerait que les lignes où la valeur de la colonne associée est égale à la valeur du filtre. Ce n'est pas tout à fait ce dont j'ai besoin.

Mon tableau comporte plusieurs colonnes. Deux d'entre eux sont appelés "clés" et "échec", string et boolean respectivement. Quand je vais rendre ces champs de filtre au-dessus de la table, j'ai besoin d'une étiquette personnalisée pour le filtre "échoué". Le filtrage pour la colonne " clé "doit correspondre à la valeur du filtre avec toute soustraction des valeurs de la" clé". Par exemple, si j'ai des valeurs clés de "abc", "abac", et "def", une valeur de filtre de "a" résultera dans les deux premières entrées montrant, et ne montrant pas l'entrée "def".

mise à Jour:

en rapport avec ceci, j'aimerais savoir comment faire quelque chose comme ceci:

disons que j'ai une expression ngRepeat dans mon élément de table comme ceci, en utilisant des filtres angularjs "standard":

"item in $data | customfilter:param | anothercustomfilter:param"

nous savons que cela ne fonctionne pas tout à fait, car ces filtres ne s'appliqueront qu'à une tranche de page obtenue à partir de la méthode "getData ()". Ce que j'aimerais vraiment pouvoir faire dans ma méthode " getData ()" c'est simplement accéder à toute la chaîne de filtrage, y compris les expressions paramétriques, et simplement y passer un tableau différent, étant la liste complète des données originales, pas seulement la tranche de page.

en même temps, j'aurais besoin d'être capable de "désactiver" le filtrage angularjs fait par lui-même, en exécutant cette chaîne de filtrage dans son traitement normal.

cela semble difficile, mais je trouve que l'API actuelle nécessite beaucoup de couplage entre le html et le javascript. Ce serait bien si le html pouvait spécifier le filtrage désiré, et le javascript utiliserait juste toute la chaîne de filtrage, mais l'utiliserait sur le liste de données complète, pas seulement la tranche de page.

mise à Jour:

voici un extrait pertinent de mon HTML:

<label for="keysFilter">Filter Keys:</label>
<input id="keysFilter" type="text" ng-model="keysFilter"/>
<label for="showOnlyFailed">Show only queries that failed?</label>
<input id="showOnlyFailed" type="checkbox" ng-model="showOnlyFailed"/>
<table ng-table="tableParams" table-pagination="custom/pages" class="table">
<tr ng-repeat="queryInfo in $data"> <!--  | filterFailed:showOnlyFailed | filterMatchingKeys:keysFilter -->

Voici mon code tableParams:

$scope.tableParams  = new ngTableParams({
    page: 1,
    count: 10,
    sorting: {
        lastRun: 'desc'
    }
},
{
    debugMode: true,
    total:  $scope.completedQueries.length,
    getData:    function($defer, params) {
        var orderedData = params.sorting() ?
                $filter('orderBy')($scope.completedQueries, params.orderBy()) :
                data;
        orderedData = $filter('filterFailed')(orderedData, $scope.showOnlyFailed);
        orderedData = $filter('filterMatchingKeys')(orderedData, $scope.keysFilter);

        params.total(orderedData.length);
        $defer.resolve(orderedData.slice((params.page() - 1) * params.count(),
                                                     params.page() * params.count()));
    }
});

notez que j'ai utilisé ce ngTable sans utiliser la liste" $data", et en itérant simplement dans ma liste" completedQueries". Quand ça marchait comme ça, la liste changeait immédiatement quand j'ai cliqué sur la case" Show only queries that failed", ou entré du texte dans le champ d'entrée "keysFilter".

cependant, maintenant que j'utilise la liste" $data", rien ne se passe quand je change l'un ou l'autre de ces champs. En fait, j'ai même ajouté $ watch-es pour ces deux champs, et aucun d'eux ne tire. Cependant, quand je fais des changements à l'un ou l'autre de ces champs, je sais que les données de la table sont réévaluées, parce que deux des colonnes ont des données qui devraient être des millis, et j'ai un filtre personnalisé sur ces colonnes qui traduisent la valeur à un "time ago" Français expression, comme" il y a 30 secondes", ou" il y a 2 minutes", et chaque fois que je change un de ces champs d'entrée, je vois ces expressions dans la table change, mais il ne fait toujours pas le filtrage approprié.

Si c'est important, voici les $regarder es-ce que j'ai ajouté à ma portée. Ces n'apparaissent jamais au feu:

    $scope.$watch("showOnlyFailed", function() {
    $scope.tableParams.reload();
});

$scope.$watch("keysFilter", function() {
    $scope.tableParams.reload();
});

Notez que lorsque je les ai commenté, je vois le message d'erreur suivant après que j'ai frappé mon "getData()" de la méthode:

Error: settings.$scope is null
@http://localhost:8000/js/diag/libs/ng-table.src.js:411
qFactory/defer/deferred.promise.then/wrappedCallback@http://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.js:11046
qFactory/ref/<.then/<@http://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.js:11132
Scope.prototype.$eval@http://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.js:12075
Scope.prototype.$digest@http://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.js:11903
Scope.prototype.$apply@http://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.js:12179
bootstrap/doBootstrap/<@http://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.js:1341
invoke@http://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.js:3762
bootstrap/doBootstrap@http://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.js:1340
bootstrap@http://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.js:1353
angularInit@http://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.js:1301
@http://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.js:21048
n.Callbacks/j@http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js:2
n.Callbacks/k.fireWith@http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js:2
.ready@http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js:2
K@http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js:2
http://ajax.googleapis.com/ajax/libs/angularjs/1.2.14/angular.js
Line 9509

C'est la bloc de code:

            $defer.promise.then(function (data) {
            settings.$loading = false;
            log('ngTable: current scope', settings.$scope);
            if (settings.groupBy) {
                self.data = settings.$scope.$groups = data;
            } else {
                self.data = settings.$scope.$data = data; // line 411
            }
            settings.$scope.pages = self.generatePagesArray(self.page(), self.total(), self.count());
        });

mise à Jour:

Voici mon plunkr cela démontre que changer les champs de filtre externes ne fonctionne pas. J'ai également deux $ watch-es commenté pour essayer de rectifier cela. Quand je commente ceux-ci, je reçois une erreur dans ng-table, se plaignant d'une portée nulle.

mise à Jour:

j'ai essayé d'ajouter les paramètres "newvalue, oldvalue" à mon $watch-es (j'ai mis à jour le plunkr). Maintenant les modifications apportées aux champs provoquent la mise à jour de la table. Malheureusement, j'ai toujours la trace de la pile sur la ligne 411 de la table ng.

12
demandé sur David M. Karr 2014-03-17 20:02:09

3 réponses

vous n'avez pas besoin des montres ni des filtres personnalisés que vous avez créés. Effectivement angulaire du "filtre" filtre est assez puissant.

vous avez juste besoin de créer un objet qui garde la trace de vos valeurs de filtre avec des membres qui correspondent à vos champs d'items. Quelque chose comme cela.

$scope.filter = {
    key: undefined,
    failed: undefined
}

alors vous pouvez le ramener à l'intérieur de la getData rappel à l'aide de params.filter(). J'ai mis à jour votre plunker ici. Vous pouvez également vérifier l'échantillon ci-dessous:

var app = angular.module('main', ['ngTable']);

app.controller('MainCtrl', function($scope, $http, $filter, ngTableParams) {

    $scope.completedQueries = [{"key":"abc000","lastRun":123,"lastSuccessfulTime":9999,"elapsedTime":456,"rows":10,"failed":false},{"key":"abc001","lastRun":1234,"lastSuccessfulTime":9999,"elapsedTime":456,"rows":10,"failed":false},{"key":"abc002","lastRun":111111111,"lastSuccessfulTime":9999,"elapsedTime":456,"rows":10,"failed":true},{"key":"abc003","lastRun":123,"lastSuccessfulTime":9999,"elapsedTime":456,"rows":10,"failed":false},{"key":"abc004","lastRun":1234,"lastSuccessfulTime":9999,"elapsedTime":456,"rows":10,"failed":true},{"key":"abc005","lastRun":111111111,"lastSuccessfulTime":9999,"elapsedTime":456,"rows":10,"failed":false},{"key":"abc006","lastRun":123,"lastSuccessfulTime":9999,"elapsedTime":456,"rows":10,"failed":false},{"key":"abc007","lastRun":1234,"lastSuccessfulTime":9999,"elapsedTime":456,"rows":10,"failed":false},{"key":"abc008","lastRun":111111111,"lastSuccessfulTime":9999,"elapsedTime":456,"rows":10,"failed":false},{"key":"abc009","lastRun":123,"lastSuccessfulTime":9999,"elapsedTime":456,"rows":10,"failed":false},{"key":"abc010","lastRun":1234,"lastSuccessfulTime":9999,"elapsedTime":456,"rows":10,"failed":false},{"key":"abc011","lastRun":111111111,"lastSuccessfulTime":9999,"elapsedTime":456,"rows":10,"failed":false},{"key":"abc012","lastRun":123,"lastSuccessfulTime":9999,"elapsedTime":456,"rows":10,"failed":true},{"key":"abc013","lastRun":1234,"lastSuccessfulTime":9999,"elapsedTime":456,"rows":10,"failed":false},{"key":"abc014","lastRun":111111111,"lastSuccessfulTime":9999,"elapsedTime":456,"rows":10,"failed":false},{"key":"abc015","lastRun":123,"lastSuccessfulTime":9999,"elapsedTime":456,"rows":10,"failed":true},{"key":"abc016","lastRun":1234,"lastSuccessfulTime":9999,"elapsedTime":456,"rows":10,"failed":false},{"key":"abc017","lastRun":111111111,"lastSuccessfulTime":9999,"elapsedTime":456,"rows":10,"failed":false}];
    $scope.filter = {
        key: undefined,
        failed: undefined
    };
    $scope.tableParams =  new ngTableParams({
        page: 1,
        count: 10,
        filter: $scope.filter
    }, {
        debugMode: true,
        total: $scope.completedQueries.length,
        getData: function($defer, params) {
            var orderedData = params.sorting() ? $filter('orderBy')($scope.completedQueries, params.orderBy()) : data;
            orderedData	= $filter('filter')(orderedData, params.filter());
            params.total(orderedData.length);
            $defer.resolve(orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count()));
        }
    });
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/ng-table/0.3.3/ng-table.min.css" rel="stylesheet"/>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ng-table/0.3.3/ng-table.min.js"></script>
<div  ng-app="main"  ng-controller="MainCtrl">
  <label for="keysFilter">Filter Keys:</label>
  <input id="keysFilter" type="text" ng-model="filter.key"/>
  <label for="showOnlyFailed">Show only queries that failed?</label>
  <input id="showOnlyFailed" type="checkbox" ng-model="filter.failed"/>
  <br/>
  <table ng-table="tableParams" class="table">
    <tr ng-repeat="queryInfo in $data">
        <td data-title="'Key'" sortable="'key'">{{queryInfo.key}}</td>
        <td data-title="'Last Run'" sortable="'lastRun'">{{queryInfo.lastRun}}</td>
        <td data-title="'Last Successful Run'" sortable="'lastSuccessfulRun'">{{queryInfo.lastSuccessfulRun}}</td>
        <td data-title="'Elapsed Time'" sortable="'elapsedTime'">{{queryInfo.elapsedTime}} ms</td>
        <td data-title="'Rows'" sortable="'rows'">{{queryInfo.rows}}</td>
        <td data-title="'Failed'" sortable="'failed'">{{queryInfo.failed}}</td>
        <td data-title="''"><button class="btn">Detail</button></td>
    </tr>
  </table> 
<div>
8
répondu cleftheris 2015-04-15 17:34:31

on dirait que vous éprouvez un problème avec ng-table elle-même, qui est une bibliothèque tierce partie qui n'est pas vraiment bien prise en charge.

en guise de preuve, consultez leur page Github, qui compte plus de 200 numéros ouverts et 1200 étoiles (1: 6):

https://github.com/esvit/ng-table

comparez ceci à une bibliothèque comme D3.js, qui bénéficie du plein soutien technique et financier du New York Times. Il a 150 numéros et plus 30,000 étoiles (1:200).

https://github.com/mbostock/d3

un grand nombre de problèmes ouverts signifie que les gens trouvent des bogues plus rapidement que les développeurs peuvent les résoudre. Il est plus que probable que les développeurs se sont tournés vers de nouveaux projets et ne sont plus intéressés à entretenir cette bibliothèque.

En d'autres termes, vous avez une limitation de fonctionnalité de la bibliothèque elle-même. Lorsque cela se produit, vous avez deux options,

1. Arrêtez d'utiliser la bibliothèque et sélectionnez une nouvelle bibliothèque, ou construisez la vôtre.

malheureusement j'ai regardé dans ceci et il n'y a pas vraiment une bonne bibliothèque de table angulaire en ce moment

2. Dévier le dépôt, apprendre le fonctionnement interne de la bibliothèque, mettre en œuvre la fonctionnalité que vous voulez vous-même, et faire une demande pull.

ce n'est donc pas une totale déception, peut-être UI-Grid peut vous aider où ng-table a échouer.

http://ui-grid.info/

Divulgation: je ne suis pas affilié avec l'interface utilisateur de la grille et je suis encore très indécis quant à savoir si elle est encore bonne

4
répondu Code Whisperer 2015-02-13 21:19:17

dans notre situation nous avons utilisé ng-table-dynamic pour avoir un ensemble de colonnes personnalisées ces colonnes personnalisées doit être map sur la liste des utilisateurs de la base de données au niveau du code. Puisque la cartographie se fait manuellement au niveau du code, nous trouvons une façon unique de gérer le filtrage et le tri avec ng-table-dynamic.

Voici le code


          function initialize() {
    this.$scope.userList = new this.NgTableParams({
          page: 1,
          count: 10
        }, {
          counts: [],
          total: this.usersList.length,
          getData: (params) => { // handles custom sorting or filtering
            var results= [];


            //add logic here if any
            results = this.$filter('filter')(results, this.$scope.searchKey);

            params.total(results.length);
            pages = Math.ceil(params.total()/ params.count());
            if(pages > 1){
              results = results.slice((params.page() - 1)* params.count(), params.page() * params.count());
            }
            return results;
          }
        });
    }

Note: Nous avons utilisé une variable déclarée résultats, où il contiendra les données à rendre à la table.

Également dans le contrôleur, nous avons besoin de gérer la recherche personnalisée

voici le code:


    this.$scope.$watch('searchKey',(newValue)=>{
          if(typeof newValue !== 'undefined'){
            this.$scope.userList.reload();// cause re-render of result in key-press
          }
    });

Ce code va déclencher la fonction getData de NgTableParams, vous permettant de construire votre filtre personnalisé.

Note: vous devez également préserver le tableau de résultats pour que vous ayez besoin de stocker dans la variable $ scope

Code ressemblera à ceci


    function foo() {
        Provider('Method', (error, users) => {
          if (!error) {
            this.usersList  = users;
            this.$scope.userList.reload(); // cause render of results to the table
            this.$scope.$apply();
          }
        });
      }

0
répondu Kevin Alviola 2017-04-25 04:29:38