AngularJS - 如何获取ngRepeat过滤后的结果引用

129

我正在使用带有筛选器的ng-repeat指令,像这样:

ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4"

我可以看到渲染后的结果,现在我想在我的控制器中对该结果运行一些逻辑。问题是如何获取结果项的引用?

更新:


仅澄清一下:我正在尝试创建自动完成,我有这个输入:

<input id="queryInput" ng-model="query" type="text" size="30" placeholder="Enter query">

然后是筛选后的结果:

<ul>
   <li  ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4">{{item.name}}</li>
</ul>

现在我想浏览这个结果并选择其中一个项目。

6个回答

274

更新:这里有比以前更容易的方法。

 <input ng-model="query">
 <div ng-repeat="item in (filteredItems = (items | orderBy:'order_prop' | filter:query | limitTo:4))">
   {{item}}
 </div>

然后$scope.filteredItems就可以被访问。


3
这种方法的问题在于,如果您监视了指定属性,您将结束$digests的垃圾邮件(每次迭代一个)...也许有某种方法可以避免这种情况? - Juho Vepsäläinen
另一种方法是在您的控制器中$watch传入的项目,并在每次传入的项目更改时执行该操作。 - Andrew Joslin
1
如果我观察搜索对象并且在控制台打印“filteredItems”,我总是会得到一个延迟一个筛选的数据。它不是刚更改的筛选结果,而是上一次更改的结果。有什么想法吗? - ProblemsOfSumit
4
有人能解释一下这个为什么有效吗?我可以理解$scope中的变量在repeat作用域中是可访问的(作用域继承),但反过来呢?怎么做到的?希望提供一些文档资料。谢谢。 - dalvarezmartinez1
如果您尝试从指令外部访问过滤数组,并且出现了摘要垃圾邮件,只要您只需要arr的长度,就将其绑定到新变量而不是传递整个结果集。 - George Kagan
显示剩余7条评论

30

这是Andy Joslin解决方案的版本过滤器。

更新: 重大更改。从1.3.0-beta.19版本开始(此提交),过滤器不再具有上下文,this将绑定到全局作用域。您可以将上下文作为参数传递,或在ngRepeat中使用新的别名语法,1.3.0-beta.17+.

// pre 1.3.0-beta.19
yourModule.filter("as", function($parse) {
  return function(value, path) {
    return $parse(path).assign(this, value);
  };
});

// 1.3.0-beta.19+
yourModule.filter("as", function($parse) {
  return function(value, context, path) {
    return $parse(path).assign(context, value);
  };
});

那么在您的看法中

<!-- pre 1.3.0-beta.19 -->
<input ng-model="query">
<div ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4 | as:'filteredItems'">
 {{item}}
</div>

<!-- 1.3.0-beta.19+ -->
<input ng-model="query">
<div ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4 | as:this:'filteredItems'">
 {{item}}
</div>

<!-- 1.3.0-beta.17+ ngRepeat aliasing -->
<input ng-model="query">
<div ng-repeat="item in items | orderBy:'order_prop' | filter:query | limitTo:4 as filteredItems">
 {{item}}
</div>

这将使您可以访问$scope.filteredItems


谢谢!你能解释一下过滤器代码是如何工作的吗?我不熟悉$parse,而且Angular文档也没有帮助我准确理解你的过滤器是如何工作的。 - Magne
2
@Magne 没问题!请查看更新,因为它可能会为您节省一些将来的痛苦和折磨。简而言之,$parse是Angular的表达式编译器。例如,它将获取字符串“some.object.property”,并返回一个函数,允许您在指定的上下文中设置或获取该路径上的值。我正在这里使用它来设置$scope上的过滤结果。希望这回答了您的问题。 - kevinjamesus86

24

尝试像这样做,ng-repeat的问题在于它会创建子作用域,因此您无法从控制器中访问

filteritems

<li ng-repeat="doc in $parent.filteritems = (docs | filter:searchitems)" ></li>

17

更新:

即使在1.3.0版本之后,如果你想将其放置在控制器或父级的范围内,你不能使用as语法进行操作。 例如,如果我有以下代码:

<div>{{labelResults}}</div>
<li ng-repeat="label in (labels | filter:query | as labelResults)">
</div>

上述方法无法生效。 解决办法是使用$parent,代码如下:

<li ng-repeat="label in ($parent.labelResults = (labels | filter:query))">

值得注意的是,如果您在此处使用了limitTo过滤器,则不会反映在$parent.labelResults中。 - Zack
如果我运行console.log labelResults,我总是会得到延迟一个筛选器后的数据。它不是刚更改的筛选器的结果,而是上一个更改的筛选器的结果。你没有遇到这个问题吗? - Anna

10
我想到了一个稍微更好的版本,基于Andy的解决方案。在他的解决方案中,ng-repeat会在包含分配的表达式上放置一个观察器。每个digest循环都会评估该表达式并将结果分配给作用域变量。
这种解决方案的问题是,如果您处于子范围内,可能会遇到分配问题。这就是为什么您应该在ng-model中使用dot的相同原因。
我不喜欢这个解决方案的另一件事是它将过滤后的数组的定义埋藏在视图标记中的某个地方。如果它在视图或控制器中的多个位置使用,可能会让人感到困惑。
一个更简单的解决方案是,在控制器中放置一个观察器,观察一个执行分配的函数:
$scope.$watch(function () {
    $scope.filteredItems = $scope.$eval("items | orderBy:'order_prop' | filter:query | limitTo:4");
});

这个函数将在每个digest周期中进行评估,因此性能应与Andy的解决方案相当。您还可以在函数中添加任意数量的赋值,以使它们都位于一个地方,而不是散布在视图中。

在视图中,您只需直接使用过滤列表:

<ul>
    <li  ng-repeat="item in filteredItems">{{item.name}}</li>
</ul>

这里有一个示例,展示了更加复杂的情况。


超级干净,不会破坏结构,很棒! - kuzyn
这个解决方案非常适合我。我之前使用的是Ionic的collection repeat而不是ng repeat,所以被接受的答案对我没用。 - Lakshay Dulani

-2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接