角度.js分页过滤的数据并显示总项目,而无需在视图/控制器中复制代码

Angular.js paginate filtered data and display total items without duplicating code in view/controller

本文关键字:视图 控制器 代码 复制 过滤 分页 js 数据 项目 显示 角度      更新时间:2023-09-26

假设我在这样的视图中实现了一个过滤器:

<input data-ng-model="statementFilter" />
<ul>
    <li data-ng-repeat="statement in statements | filter: statementFilter">
        {{ statement.Name }}
    </li>
</ul>

这将对具有包含 statementFilter 的任何属性的语句进行不区分大小写的部分匹配。

我需要在我的控制器中实现这一点,而不是在我的视图中。 我知道您可以在 Angular 中创建自定义过滤器,但我希望我的过滤器对视图中内置的 Angular 过滤器所做的任何复杂对象进行不区分大小写的通用部分匹配。 如果我创建自定义过滤器,我必须使用 javascript 进行实际过滤,这将需要另一个库 AFAIK。

如何在代码中利用 Angular 的"视图"过滤器附带的不区分大小写的通用部分匹配?

谢谢

更新

这是我正在尝试做的事情的Plunker。

解决方案:http://plnkr.co/edit/AcAP437OJGMgMuGCtxT3?p=preview


基本上,问题在于控制器正在执行您知道可以在视图中完成的事情......使这比大多数其他情况更困难的是,您正在尝试对正在过滤和显示长度的相同数据进行分页......因此,这意味着您的数据必须按以下顺序进行操作:

  1. 基于搜索项筛选的数据
  2. 捕获筛选项目的长度
  3. 对筛选的项目进行分页并显示

我知道必须做的第一件事是返工ng-repeat以进行过滤。目标是在角度过滤中使用该构建。

最初,它看起来像这样。它进行了过滤和分页,但在控制器中使用了自定义代码。

data-ng-repeat="statement in pagedStatementData()"

第 1 步:使用角度滤镜

您在问题中发布的过滤是一种更简单的方法,无需编写自定义过滤代码......这就是我的第一步。足够简单。

data-ng-repeat="statement in statements | filter:statementFilter"

第 2 步:恢复分页

此时,列表已正确筛选,但显示所有筛选的项目,并且不会将它们分成页面。分页按钮按预期工作,总记录也会相应更新。因此,现在下一步是将该分页插入到此过滤列表中。

在脚本中,我向范围添加了开始和结束。这些变量之前是在pagedStatementData() 中创建的。然后使用这些值,我可以对过滤后的数组进行切片以使分页继续进行。

注意此 $scope.begin $scope.end 代码最终在第 5 步中删除,因为它仅在初始渲染时计算,之后不会更新。这是一个直到第 5 步我才注意到的错误。

$scope.begin = ($scope.currentPage-1)*$scope.numPerPage;
$scope.end = ($scope.begin + $scope.numPerPage);
data-ng-repeat="statement in (statements | filter:statementFilter).slice(begin, end)"

步骤 3:删除不需要/不需要的控制器代码

在这一点上,一切正常...但目标是删除自定义过滤代码...所以我删除了$scope.filteredStatementData方法和调用它的$scope.totalFilteredStatementItems方法。 $scope.pagedStatementData也可以被删除。在步骤 1 中修改的ng-repeat中调用。

已删除

  • $scope.filteredStatementData//自定义过滤器代码.. 已删除
  • $scope.totalFilteredStatementItems//call filteredStatementData...删除
  • $scope.pagedStatementData//这是由原始的 ng-repeat...删除

步骤4:修复总项目#和分页按钮。两者都依赖于相同的 .length

此时...视图已损坏,因为它仍在对我们刚刚删除的方法进行一些调用。(总筛选语句项目(因此,现在的目标是将该功能替换为视图中的功能。totalFilteredStatementItems 用于运行该自定义筛选逻辑,然后在不对数据进行分页的情况下获取长度。

我们已经筛选了项目,因此我们只需要将它们保存到范围(在它们被分页之前(,以便可以在其他地方访问它们。实际上,我们可以将该过滤后的数组保存在 ng-repeat 中。只要语法保持item in items...但是items可以分配给范围变量...喜欢item in (items = (/*filter*/)).slice(x,y)

data-ng-repeat="statement in (filteredItems = (statements | filter:statementFilter)).slice(being, end)"    
<div>Total records: {{ filteredItems.length }}</div>
<pagination data-ng-model="currentPage" total-items="filteredItems.length"

好。这种重复开始变得疯狂,但它仍然有效。圆圈是这里真正的魔力。此代码按所需顺序执行。

// filtered data based on search item
$scope.filteredItems = $scope.statements.filter(/*statementFilter magic*/);
// paginate the filtered items
var _temp = filteredItems.slice($scope.begin, $scope.end),
    _i, statement;
// display page of filtered items
for (var _i in _temp) {
    statement = _temp[_i];
    // Render each row w/ statement
}

另外,我确信有一些 Angular $scope魔法正在更新过滤的 Items.length,因为它在过滤列表之前在 Total records:div 中使用......谢谢角度!或者,也许它会优先考虑 ng-repeat 并首先执行该块。艾德克。它有效。


第 5 步:分页已损坏。获取分页组件以更新列表所依赖的开始和结束变量。

删除了控制器中的$scope.begin 和 $scope.end 代码。首次创建组件时,在ng-init中创建它们,然后在 data-ng-change 事件上重新计算这些值。

<pagination data-ng-model="currentPage" total-items="filteredItems.length"
    items-per-page="numPerPage" data-max-size="maxSize" data-boundary-links="true"
    ng-init="begin = (currentPage-1)*numPerPage; end = begin + numPerPage"
    data-ng-change="begin = (currentPage-1)*numPerPage; end = begin + numPerPage">

这是另一种通过多个过滤器和分页实现相同目标的方法。与Cory的答案相比,实际上没有任何优势,除了这个版本不依赖于分页控件的角度UI。

应用.js

var app = angular.module('statementApp', ['ui.bootstrap']);
app.controller('statementController', function($scope, $interpolate) {
$scope.currentPage = 0;
$scope.pageSize = 10;
$scope.data = [
{name:"John Smith", price:"1.20"},
{name:"John Smith", price:"1.20"},
{name:"Sam Smith", price:"1.20"},
{name:"Sam Smith", price:"1.20"},
{name:"Sam Smith", price:"1.20"},
{name:"Sam Smith", price:"1.20"},
{name:"Sarah Smith", price:"1.20"},
{name:"Sarah Smith", price:"1.20"},
{name:"Sarah Smith", price:"1.20"},
{name:"Sarah Smith", price:"1.20"},
{name:"Sarah Smith", price:"1.20"},
{name:"Sarah Smith", price:"1.20"}
];
var init = function() {
  $scope.initPaging();
}

$scope.searchFilter = function(item) {
  if(!$scope.searchVal) return true;
  var qsRegex = new RegExp($scope.searchVal, 'gi');
  return qsRegex ? item.name.match(qsRegex) : true;
}
    $scope.initPaging = function() {
                $scope.currentPage = 0;
                $scope.numberOfPages=function(){
                        if($scope.filteredItems.length > $scope.pageSize) {
                        return Math.ceil($scope.filteredItems.length / $scope.pageSize);
                    }
                    return 1;
                }
            }
$scope.$watch(function () {
                $scope.filteredItems = $scope.$eval("data | filter:searchFilter | orderBy: 'price'");
            });
  init();
});

索引.html

<!DOCTYPE html>
<html ng-app="statementApp">
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.12.0.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
<script src="script.js"></script>
  </head>
  <body ng-controller="statementController">
<input id="txtStatementFilter" class="form-control" ng-model="searchVal" placeholder="Search records" />
   <div>Total records: {{ filteredItems.length }}</div>
<table class="table table-hover table-bordered table-striped table-condensed">
    <thead>
        <tr>
            <th>Name</th>
            <th>Price</th>
        </tr>
    </thead>
    <tbody>
        <tr ng-repeat="item in (filteredItems).slice(currentPage*pageSize,(currentPage*pageSize) + pageSize)">
                <td>{{item.name}}</td>
                <td>{{item.price | currency:"£":0}}</td>
            </tr>
    </tbody>
</table>
   <button ng-disabled="currentPage == 0" ng-click="currentPage=currentPage-1">
            Previous
        </button>
        {{currentPage+1}}/{{numberOfPages()}}
        <button ng-disabled="currentPage >= filteredItems.length/pageSize - 1" ng-click="currentPage=currentPage+1">
            Next
        </button>
  </body>
</html>

Plunker link http://plnkr.co/edit/OWotCiVYBed77F50wdMf?p=preview