12

我正在尝试使用 ngTable 构建一个表,但自定义过滤与 ngTable page 中的示例中描述的不同。

我想要就地过滤,但我不希望 ngTable 呈现过滤器选择器。我想自己渲染它们(在表格上方),然后在我的“getData()”方法中引用它们。

前面提到的例子并没有解释这些机器是如何工作的。我不知道每个“td”元素的“filter”属性中需要指定什么。我了解 AngularJS $filter 函数的基本语法,但我不清楚 ngTable 对此做了什么。从一个示例中,看起来我只能进行“等于”检查,这只会选择关联列值等于过滤器值的行。这不是我所需要的。

我的表有几列。其中两个被称为“key”和“failed”,分别是字符串和布尔值。当我在表格上方呈现这些过滤器字段时,我需要一个“失败”过滤器的自定义标签。过滤“key”列应将过滤器值与“key”值的任何子字符串匹配。例如,如果我的键值为“abc”、“abac”和“def”,则过滤器值“a”将导致前两个条目显示,而不显示“def”条目。

更新:

与此相关,我希望我能弄清楚如何做这样的事情:

假设我的表格元素中有一个 ngRepeat 表达式,使用“标准”angularjs过滤器:

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

我们知道这不太有效,因为这些过滤器仅适用于从“getData()”方法获得的一个页面切片。我真正希望能够在我的“getData()”方法中做的是简单地访问整个过滤器链,包括参数表达式,并简单地将不同的数组传递给它,作为整个原始数据列表,而不仅仅是页面切片。

同时,我需要能够通过在正常处理中执行该过滤器链来“关闭” angularjs 自身正在执行的过滤。

这听起来很困难,但我发现当前的 API 需要在 html 和 javascript 之间进行大量耦合。如果 html 可以指定所需的过滤,那就太好了,并且 javascript 将只使用整个过滤器链,但在整个数据列表上使用它,而不仅仅是页面切片。

更新:

这是我的 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 -->

这是我的 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()));
    }
});

请注意,我使用的这个 ngTable 没有使用“$data”列表,而只是遍历了我的“completedQueries”列表。当它这样工作时,当我单击“仅显示失败的查询”复选框或在“keysFilter”输入字段中输入文本时,列表将立即更改。

但是,既然我使用的是“$data”列表,那么当我更改其中任何一个字段时都不会发生任何事情。事实上,我什至为这两个字段都添加了 $watch-es,但它们都没有触发。但是,当我对这些字段中的任何一个进行更改时,我知道正在重新评估表数据,因为其中两列具有预期为毫秒值的数据,并且我对那些将值转换为的列有一个自定义过滤器一个“时间前”的英文表达,如“30 秒前”或“2 分钟前”,每次我更改其中一个输入字段时,我都会看到表中的这些表达式发生变化,但它仍然没有适当的过滤。

如果重要的话,这里是我添加到我的范围的 $watch-es。这些似乎永远不会触发:

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

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

请注意,当我对这些进行评论时,在我点击“getData()”方法后会看到以下错误:

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

这是相关的代码块:

            $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());
        });

更新:

这是我的plunkr,它证明更改外部过滤器字段不起作用。我也有两个 $watch-es 被注释掉以试图纠正这个问题。当我在其中发表评论时,我在 ng-table 中收到一个错误,抱怨为空范围。

更新:

我尝试将“newvalue,oldvalue”参数添加到我的 $watch-es(我更新了 plunkr)。现在对字段的更改导致表更新。不幸的是,我仍然在 ng-table 的第 411 行得到那个堆栈跟踪。

4

3 回答 3

8

您不需要手表,也不需要您创建的自定义过滤器。实际上 Angular 的“过滤器”过滤器非常强大。

您只需要创建一个对象,该对象使用与您的项目字段匹配的成员来跟踪您的过滤器值。像这样的东西。

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

然后您可以getData使用params.filter(). 我在这里更新了你的 plunker。您还可以查看以下示例:

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>

于 2015-04-15T17:34:31.317 回答
4

看起来您自己遇到了问题ng-table,这是一个没有得到很好支持的 3rd 方库。

作为证据,请查看他们的 Github 页面,该页面有 200 多个未解决的问题和 1,200 颗星 (1:6):

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

将此与类似 的图书馆进行比较D3.js,后者享有《纽约时报》的全面技术和财务支持。它有 150 期和超过30,000颗星 (1:200)。

https://github.com/mbostock/d3

大量未解决的问题意味着人们发现错误的速度比开发人员解决问题的速度要快。开发人员很可能已经转移到新项目并且不再对维护这个库感兴趣。

换句话说,您遇到了库本身的功能限制。发生这种情况时,您有两种选择,

1.停止使用该库并选择一个新库,或者构建自己的库。

可悲的是,我已经对此进行了研究,现在还没有一个非常好的角度表库

2. fork 存储库,了解库的内部工作原理,自己实现您想要的功能,并提出拉取请求。

就这样,这并不是一个完全无赖,也许UI-Grid可以帮助你ng-table失败的地方。

http://ui-grid.info/

披露:我不隶属于 ui-grid 并且对于它是否好用仍然持怀疑态度

于 2015-02-13T20:23:42.470 回答
0

在我们的情况下,我们使用 ng-table-dynamic 来拥有一组自定义列,这些自定义列需要在代码级别映射到数据库中的用户列表。由于映射是在代码级别手动发生的,我们找到了一种使用 ng-table-dynamic 处理过滤和排序的独特方法。

这是代码

          函数初始化(){
    this.$scope.userList = new this.NgTableParams({
          页数:1,
          计数:10
        }, {
          计数:[],
          总计:this.usersList.length,
          getData: (params) => { // 处理自定义排序或过滤
            变种结果= [];
            
            
            //如果有的话,在这里添加逻辑
            结果 = this.$filter('filter')(results, this.$scope.searchKey);
           
            params.total(results.length);
            pages = Math.ceil(params.total()/params.count());
            如果(页面 > 1){
              结果 = results.slice((params.page() - 1)* params.count(), params.page() * params.count());
            }
            返回结果;
          }
        });
    }

注意:我们使用了一个声明的变量 results,它将包含要呈现到表的数据。

同样在控制器中,我们需要处理自定义搜索

这是代码:

    this.$scope.$watch('searchKey',(newValue)=>{
          if(typeof newValue !== '未定义'){
            this.$scope.userList.reload();// 导致按键重新渲染结果
          }
    });

此代码将触发 NgTableParams 的 getData 函数,允许您构建自定义过滤器。

注意:您还需要保留结果数组,因此您需要存储在 $scope 变量中

代码将如下所示

    函数 foo() {
        Provider('Method', (error, users) => {
          如果(!错误){
            this.usersList = 用户;
            this.$scope.userList.reload(); // 将结果渲染到表中
            this.$scope.$apply();
          }
        });
      }

于 2017-04-07T04:51:49.497 回答