在ng-repeat中使用ng-if检查值是否在数组中

26
我有一个使用ng-repeat遍历从API获取的葡萄酒列表。我还有一个包含所有已添加到收藏夹的葡萄酒ID的数组变量,这些ID是从数据库中获取的。如果用户还没有将特定结果葡萄酒添加到列表中,我希望能够显示“添加到收藏夹”按钮。为了实现这一点,我认为可以采用以下方法: HTML:
<tr ng-repeat="wine in wines">
    <td>{{$index+1}}</td>
    <td>{{ wine.Name }}</td>
    <td>{{ wine.Appellation.Name }}</td>
    <td>${{ wine.PriceMin }} - ${{ wine.PriceMax }}</td>
    <td>
        <!-- If wine.Id is not yet in the array of all favorite ids, display "Add Button" -->
        <a href="#" class="btn btn-primary btn-dark" ng-click="addToFavorites(wine.Id)" ng-if="favorites.indexOf(wine.Id) !> -1"> Add </a>
        <!-- Else Display Already Added -->
        <span ng-if="favorites.indexOf(wine.Id) > -1">Added</span>
    </td>
</tr>

以下是我的JS代码:

app.controller("MainController", function($scope, $http){
    $scope.favorites = [];
    var getAllFavorites = function(){
        $http.get("/home/getAllFavoriteIds").success(function(response) {
            angular.forEach(response, function(r) {
                $scope.favorites.push(r);
            });
        });
    };
});

我对 .indexOf() 不是很了解,所以我认为问题可能出在这里。但也有可能是我错了。


2
这是一个可工作的示例,请参考 :) http://plnkr.co/edit/FVMVbKH3DpSx2yMlcSiy?p=preview - Kalhan.Toress
我已经接近了,但现在它们全部显示为假。尽管我已经将product_id输入到我的收藏数据库中。 - Wp3Dev
没关系!我必须将id值更改为字符串。id = id.toString() - Wp3Dev
5个回答

31
您可以使用angular-filter的contains过滤器
<span ng-if="favorites | contains:wine.Id">Added</span>

或者编写自己的过滤器来执行相同的操作:

angular.module('module').filter('contains', function() {
  return function (array, needle) {
    return array.indexOf(needle) >= 0;
  };
});

13

我建议您将这个逻辑移到控制器中,保持视图尽可能干净:

   $scope.isFavorites = function(id) {
       return $scope.favorites.indexOf(id) !== -1;
   }

您应该看到:

<!-- If wine.Id is not yet in the array of all favorite ids, display "Add Button" -->
<a href="#" class="btn btn-primary btn-dark" ng-click="addToFavorites(wine.Id)" ng-if="!isFavorites(wine.Id)">Add</a>
<!-- Else Display Already Added -->
<span ng-if="isFavorites(wine.Id)>Added</span>

1
你应该能够跳过“|| false”,只需执行“return ($scope.favorites.indexOf(id) > -1);”。代码稍微简洁一些 :) - Mattias

7
我认为你需要进行更改。
favorites.indexOf(wine.Id) !> -1

转化为

favorites.indexOf(wine.Id) < 0

indexOf永远不会返回小于-1的任何内容。 - charlietfl
好的,我的错,应该是<0。 - Ced

1

favorites.indexOf(wine.Id) !> -1 看起来不像是一个合适的 Angular 表达式。请注意,当您在模板中使用表达式时,只允许一些基本的 JavaScript 条件语句。请参见 docs 了解可能性。

与其拥有所有葡萄酒的列表和收藏葡萄酒的列表,最好将所有葡萄酒的列表扩展为具有布尔属性 isFavorite。这样做也更有利于性能,因为它不需要在每次迭代中搜索第二个列表中的葡萄酒。

在响应回调循环中(快速且简单):

var index = $scope.favorites.indexOf(r.id);
if(index > -1) {
  $scope.favorites[index].isFavorite = true;
} // else isFavorite is undefined, which is falsy

这样的数组操作可以更加优雅地使用UnderscoreLodash来完成。

请注意,如果您有一个包含葡萄酒的对象(键为ids),则每次不必通过索引查找来检索葡萄酒。 ngRepeat支持像数组一样的对象。

在您的模板中:

<!-- If wine.Id is not yet in the array of all favorite ids, display "Add Button" -->
<a href="#" class="btn btn-primary btn-dark" ng-click="addToFavorites(wine.Id)" ng-if="!wine.isFavorite"> Add </a>
<!-- Else Display Already Added -->
<span ng-if="wine.isFavorite">Added</span>

0

!> 不是有效的语法。! 只能与 = 或布尔值一起使用。请使用

favorites.indexOf(wine.Id) == -1

如果在数组中找不到元素,indexOf会返回-1。 感谢您的更正。我卡在!>上了。


1
我认为应该是 favorites.indexOf(wine.Id) == -1 - Kalhan.Toress
@Vohuman,K.Toress是正确的。永远不会出现< -1的情况。 - Pratik

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