ng-if、indexOf和JSON数组相关的问题解答

6

我有一个JSON输出的items - 要显示单个项目,我使用 ng-repeat="item in items"。并且我可以通过user访问当前登录的用户对象。

每个项目都可以属于多个用户的愿望清单。如果用户将项目添加到其愿望清单中,则user_id会保存在item.wishlists中。

单个item的JSON输出看起来简化如下:

{"id":1,"title":"This is a tile","wishlists":[{"user_id":2},{"user_id":3}]}

当我使用 user.id 时,会得到当前已登录用户的ID。

现在,我希望在 ng-repeat="item in items" 内使用 ng-if 来检查当前用户是否已将此项目添加到他的愿望清单中,如果是,则向该用户显示“从愿望清单中移除”按钮而不是“添加到愿望清单”。

我的错误尝试如下:

<div ng-repeat="item in items">
  <h3>{{item.title}}</h3>
  <a href="" ng-click="addToWishlist(item)" ng-if="item.wishlists.indexOf(user.id) == -1">Wish</a>
  <a href="" ng-click="removeFromWishlist(item)" ng-if="item.wishlists.indexOf(user.id) > -1">Undo-Wish</a>
</div>

我可以这样使用indexOf吗?或者什么是正确的angularJS方式来检查user.id是否在item.wishlists user_id中?
更新: 视图:(如果为真,则ctrl.hasWished将图标从“favorite”更改为“favorite_border”)
<div ng-repeat="item in items">
      <md-button class="md-icon-button feed-wish md-warn" aria-label="Wish" ng-click="ctrl.toggleWish(item)">
        <i class="material-icons">favorite{{ctrl.hasWished(item) ? '' : '_border' }}</i>
      </md-button> 
</div>

控制器:


  // Check if User has wished this item already: Should return true or false
  this.hasWished = function(item) {
    return item.wishlists.some(function(wishlist) {
      return wishlist.user_id === Auth._currentUser.id; // returns true if currently logged in user id is on wishlist
    });
  };

  this.toggleWish = function(item) {
    if (!this.hasWished) {
      this.hasWished = true;
      items.wish(item); // sends PUT request
      ToastService.show(item.product + ' added to Wish List');
    } else {
      this.hasWished = false;
      items.unWish(item); // sends DELETE request
      ToastService.show(item.product + ' removed from Wish List');
    }
  }

当我点击按钮时,如果之前它是false,它就会发送PUT请求,并且我也会收到ToastService消息“添加..”,如果我再次点击它,它就会发送DELETE请求和ToastService消息“已删除..” 但图标没有从“favorite”更改为“favorite_border”。当我重新加载页面时,正确的图标会显示。
我还在控制台中看到了这个错误信息:
TypeError: Cannot read property 'id' of null
    at http://ruby-on-rails-140223.nitrousapp.com:3000/assets/auctions/auctionCtrl-f2cb59b8ad51e03a2264ef2c6e759a54.js?body=1:33:52
    at Array.some (native)
    at hasWished (http://ruby-on-rails-140223.nitrousapp.com:3000/assets/auctions/auctionCtrl-f2cb59b8ad51e03a2264ef2c6e759a54.js?body=1:32:30)
    at fn (eval at <anonymous> (http://ruby-on-rails-140223.nitrousapp.com:3000/assets/angular/angular-81b9b668c3f93c8ccb76b27ad984d9b6.js?body=1:13323:15), <anonymous>:4:318)
    at Object.expressionInputWatch [as get] (http://ruby-on-rails-140223.nitrousapp.com:3000/assets/angular/angular-81b9b668c3f93c8ccb76b27ad984d9b6.js?body=1:14303:31)
    at Scope.$digest (http://ruby-on-rails-140223.nitrousapp.com:3000/assets/angular/angular-81b9b668c3f93c8ccb76b27ad984d9b6.js?body=1:15819:40)
    at Scope.$apply (http://ruby-on-rails-140223.nitrousapp.com:3000/assets/angular/angular-81b9b668c3f93c8ccb76b27ad984d9b6.js?body=1:16098:24)
    at done (http://ruby-on-rails-140223.nitrousapp.com:3000/assets/angular/angular-81b9b668c3f93c8ccb76b27ad984d9b6.js?body=1:10547:47)
    at completeRequest (http://ruby-on-rails-140223.nitrousapp.com:3000/assets/angular/angular-81b9b668c3f93c8ccb76b27ad984d9b6.js?body=1:10745:7)
    at XMLHttpRequest.requestLoaded (http://ruby-on-rails-140223.nitrousapp.com:3000/assets/angular/angular-81b9b668c3f93c8ccb76b27ad984d9b6.js?body=1:10686:9)

当单击时也出现了这个错误:

TypeError: v2.hasWished is not a function
    at fn (eval at <anonymous> (http://ruby-on-rails-140223.nitrousapp.com:3000/assets/angular/angular-81b9b668c3f93c8ccb76b27ad984d9b6.js?body=1:13323:15), <anonymous>:4:318)
    at Object.expressionInputWatch [as get] (http://ruby-on-rails-140223.nitrousapp.com:3000/assets/angular/angular-81b9b668c3f93c8ccb76b27ad984d9b6.js?body=1:14303:31)
    at Scope.$digest (http://ruby-on-rails-140223.nitrousapp.com:3000/assets/angular/angular-81b9b668c3f93c8ccb76b27ad984d9b6.js?body=1:15819:40)
    at Scope.$apply (http://ruby-on-rails-140223.nitrousapp.com:3000/assets/angular/angular-81b9b668c3f93c8ccb76b27ad984d9b6.js?body=1:16098:24)
    at HTMLButtonElement.<anonymous> (http://ruby-on-rails-140223.nitrousapp.com:3000/assets/angular-touch/angular-touch-b4d02ed602708a1c93b51087222e0363.js?body=1:478:13)
    at HTMLButtonElement.eventHandler (http://ruby-on-rails-140223.nitrousapp.com:3000/assets/angular/angular-81b9b668c3f93c8ccb76b27ad984d9b6.js?body=1:3299:21)

请尝试使用(item.wishlists|filter:{user_id:user.id}).length==0 - vp_arth
3个回答

4

过滤器应该起作用:

<div ng-repeat="item in items">
  <h3>{{item.title}}</h3>
  <a href="" ng-click="addToWishlist(item)" ng-if="!(item.wishlists|filter:{user_id:user.id}).length">Wish</a>
  <a href="" ng-click="removeFromWishlist(item)" ng-if="(item.wishlists|filter:{user_id:user.id}).length">Undo-Wish</a>
</div>

2
我会避免在视图中放置太多逻辑,记住关注点分离,这段代码最好放在控制器内的一个函数中。 - Ran Sasportas
如果我们想要呈现所需和不需要的用户列表,我们必须添加两个具有相同过滤器的ng-repeat块,并且所有内容都看起来很好。这不是逻辑。这只是视图选项。但我同意,在任何情况下,都需要进行优化。然后,数据源将在响应中返回布尔标记。 - vp_arth
@RanSasportas 是的,我想稍后会在控制器中实现你的示例逻辑,目前只是在后端构建删除功能的简单解决方案。 - Alessandro Santamaria

2

你不能使用indexOf函数来完成这个任务。 相反,我建议你在控制器范围内创建一个函数,以此检查愿望清单是否包含该用户。

function isUserOnWishlist(item) {
    return item.wishlists.some(function(wishlist) {
        return wishlist.user_id === user.id; // ( on $scope ? )
    });
}

在视图上 -
<a href="" ng-click="addToWishlist(item)" ng-if="!isUserOnWishlist(item.wishlists)">Wish</a>
<a href="" ng-click="addToWishlist(item)" ng-if="isUserOnWishlist(item.wishlists)">Undo-Wish</a>

isUserOnWishlist函数将遍历愿望清单上的每个用户,并仅在找到至少一个满足此条件的愿望清单时返回true - wishlist.user_id === user.id。如果愿望清单是int列表而不是对象列表,则可以使用indexOf函数。
我建议您查看MDN js数组函数文档,您可以在那里找到有关js内置的所有酷炫数组函数的解释。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array 祝你好运。

嗨,我现在正在使用它,它运行良好,但如果愿望清单为空,我会收到此错误:TypeError: Cannot read property 'id' of null at Array.some (native) - 我该如何解决这个问题呢? - Alessandro Santamaria
你确定用户变量不是空的吗? - Ran Sasportas
是的,我正在使用 return wishlist.user_id === Auth._currentUser.id 而不是 user.id。(我将更新我的问题以展示您现在正在做什么) - Alessandro Santamaria

1
不要使用indexOf方法,查看这篇文章:“还有一个方面需要考虑:等式。indexOf方法使用严格等式(===)来确定元素是否与您的搜索匹配。这对于原始类型(如字符串和数字)非常有效。但是,您可能会在使用indexOf搜索给定对象或数组时遇到困难。” 使用Array.indexOf查找数组元素
您可以使用$filter API参考/ng/filter组件中的过滤器,或者也许您应该在控制器中创建一个函数,将当前项和用户ID作为参数传递以执行此操作,或者创建一个自定义指令。如果您想要自定义函数的想法,请查看此内容:如何在JavaScript对象数组中查找项目的索引/
问候

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