1

最も古いメッセージを一番上に、最新のメッセージを一番下に表示するチャット メッセージ表示があります。アレイでを使用してng-repeatおり$scope.messages、新しいチャット メッセージがそのアレイに動的に追加されます。にはng-repeatorderByメッセージを作成日でソートするのに役立つフィルター コンポーネントがあります。

ng-ifメッセージが同じ日に同じユーザーによって送信されたときに、HTML の特定の側面 (ユーザーのアバター、名前、msg-timestamp など) を非表示にするために使用しようとしています。ただし、新しいメッセージが配列に追加されると、私のロジックは台無しになります。$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のメッセージは最後に送信されたメッセージの 2 番目 (最新ではない) のままであり、最新の最新のメッセージは実際には のアイテムです。配列の最後のインデックス。これにより、最初のステートメントが有効になり、同じ日に同じユーザーによって送信されたすべての新しいメッセージに対して HTML 要素が表示されます (ページを更新しない限り、すべてが適切に表示されます)。if

誰でも考えられる回避策はありますか?

4

2 に答える 2

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 に答える