如何正确使用ng-if与使用orderBy过滤器的ng-repeat的更新范围

时间:2015-04-16 20:19:12

标签: angularjs angularjs-scope angularjs-ng-repeat angularjs-orderby angular-ng-if

我有一个聊天消息显示屏,显示顶部最旧的消息和最近的消息。我在ng-repeat数组上使用$scope.messages,并且新的聊天消息会动态添加到该数组中。 ng-repeat有一个orderBy过滤器组件,可帮助按创建日期对邮件进行排序。

我正在尝试使用ng-if隐藏同一用户在同一天发送消息时HTML的某些方面(用户的头像,名称,消息时间戳等)。 但是,当新消息添加到$scope.messages数组时,我的逻辑就搞砸了。

缩短版HTML:

<div class="ListMessage" ng-repeat="message in messages | orderBy: 'created' track by message.xpid">
  <div class="Avatar" ng-if="headerDisplay(message)">
  </div>
  <div class="TimeStamp" ng-if="headerDisplay(message)">
  </div>
  <div class="MessageContent">
  </div>
</div>

这是适用的聊天控制器:

$scope.messages = [];

// use an HTTP service to retrieve messages...
$scope.$on('messages_updated', function(event, data){
  $scope.messages = data;
};

$scope.headerDisplay = function(message){
  var idx = $scope.messages.indexOf(message);
  var curMsg = $scope.messages[idx];
  var nextMsg;

  // if last msg in array (this is actually the 1st msg sent cuz of the orderBy) --> display avatar
  if (idx === $scope.messages.length-1){
    return true;
  }

  // if not the last msg in array (not the 1st sent)...
  if (idx !== $scope.messages.length-1){
    nextMsg = $scope.messages[idx+1];
    var nextMsgDate = new Date(nextMsg.created);
    var curMsgDate = new Date(curMsg.created);
    // if msg is on a new day --> display avatar
    if (curMsgDate.getDate() !== nextMsgDate.getDate()){
      return true;
    } else if (curMsg.fullProfile.displayName !== nextMsg.fullProfile.displayName){
      // if msg is from diff user --> display avatar
      return true;
    } else {
      return false;
    }
  }
};

此代码乍一看。最初,由于orderBy过滤器,最后一个索引$scope.messages的消息实际上是第一条消息, 0 索引处的消息是最后添加的消息。

但是每当添加新消息时,Angular会动态更新范围,并且在应用orderBy过滤器之前的一瞬间,新消息位于$scope.messages的最后一个索引处。这会抛弃我的ng-if方法背后的逻辑,以便来自同一用户的每条新消息都显示我想隐藏的HTML元素(即它返回 true on ng-if方法)。

根据我的广泛console.logging,在编译ng-if的HTML时, 0 索引处的消息仍然是最后一条消息的第二条消息发送(不是最新的),最新的,最新的消息实际上是数组的最后一个索引中的项目。这导致第一个if语句生效,并且同一用户在同一天发送的每条新消息都显示HTML元素(除非我进行页面刷新,其中所有内容都正确显示)。

任何人都能想到的解决方法吗?

2 个答案:

答案 0 :(得分:0)

这可能有用:您可以维护$scope.messages的副本并过滤该数组,所有这些都在您的JS中。然后将其复制到$scope.messages以更新UI。像这样:

$scope.addMessage(message) {
    $scope.messagesCopy.push(message);
    $scope.messages = $filter('orderBy')($scope.messagesCopy, 'created');
}

这使得对$scope.messages的任何更改都是正确的更改。唯一不好的部分是你在内存中保留了两份邮件副本

答案 1 :(得分:0)

请参阅下面的演示。

而不是在控制器中找到你的消息索引

var idx = $scope.messages.indexOf(message);

将动态索引从您的视图传递到控制器

ng-if="headerDisplay(msg, $index)"

然后在你的控制器中

$scope.headerDisplay = function(message,idx){
...

请参阅下面的示例演示

&#13;
&#13;
var app = angular.module('app', []);

app.controller('firstCtrl', function($scope) {

  $scope.messages = [{
    msg: 'hello',
    created: '1420155800000'
  }, {
    msg: 'hi',
    created: '1420153800000'
  }]


  $scope.add = function() {
    $scope.newms.created = Date.now();

    $scope.messages.push($scope.newms)

    $scope.newms = {};



  }

  $scope.headerDisplay = function(message, idx) {

    var curMsg = message
    var nextMsg;

    // if last msg in array (this is actually the 1st msg sent cuz of the orderBy) --> display avatar
    if (idx === $scope.messages.length - 1) {
      return true;
    }
  }
});
&#13;
.new {
  position: absolute;
  bottom: 0;
  width: 100%;
}
.TimeStamp {
  font-size: small;
  color: red;
}
&#13;
<!DOCTYPE html>
<html>

<head>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js"></script>

  <meta charset="utf-8">
  <title>JS Bin</title>
</head>

<body ng-app="app">
  <div ng-controller="firstCtrl">
    <div ng-repeat="message in messages |orderBy: '!created'">

      <span class="TimeStamp" ng-if="headerDisplay(msg, $index)">{{message.created | date :'dd-MMM HH:mm:ss'}}</span>
      {{message.msg}}
    </div>

    <div class="new">
      <input ng-model="newms.msg" type="text">
      <button ng-click="add()">ADD</button>
    </div>
  </div>
</body>

</html>
&#13;
&#13;
&#13;