1

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

ng-if当同一用户在同一天发送消息时,我试图用来隐藏 HTML 的某些方面(用户的头像、姓名、msg 时间戳等)。但是,当向数组添加新消息时,我的逻辑就搞砸了。$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 元素(即它在方法上返回trueng-if)。

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

任何人都可以想到的解决方法?

4

2 回答 2

0

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

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

这使得任何更改$scope.messages都是正确的更改。唯一不好的部分是您在内存中保留了两个消息副本

于 2015-04-16T20:39:26.207 回答
0

请看下面的演示。

而是在您的控制器中查找您的消息的索引

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

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

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

然后在你的控制器中

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

请参阅下面的示例演示

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;
    }
  }
});
.new {
  position: absolute;
  bottom: 0;
  width: 100%;
}
.TimeStamp {
  font-size: small;
  color: red;
}
<!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>

于 2015-04-16T21:53:21.473 回答