我有一个聊天消息显示屏,显示顶部最旧的消息和最近的消息。我在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元素(除非我进行页面刷新,其中所有内容都正确显示)。
任何人都能想到的解决方法吗?
答案 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){
...
请参阅下面的示例演示
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;