1

У меня есть отображение сообщений чата, в котором отображаются самые старые сообщения вверху и самые последние сообщения в нижней части. Я использую ng-repeat в массиве $scope.messages, и новые сообщения чата динамически добавляются в этот массив. У ng-repeat есть компонент фильтра orderBy, который помогает сортировать сообщения по дате создания.Как использовать ng-if правильно с обновленной областью ng-repeat, которая использует фильтр orderBy

Я пытаюсь использовать 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 фактически является первым сообщением, и сообщение в - это последнее добавленное сообщение.

Но всякий раз, когда добавляется новое сообщение, Угловое динамически обновляет объем, и на долю секунды до orderBy фильтра применяется, что новое сообщение на последнем индексе $scope.messages. Это отбрасывает логику моего метода ng-if, так что каждое новое сообщение от того же пользователя появляется с элементами HTML, которые я хочу скрывать (т. Е. Возвращает true по методу ng-if).

Согласно обширному console.logging с моей стороны, во время компиляции HTML для ng-if, сообщение на индекс остается второй до последнего отправленного сообщения (не самый последний), и новейший, последнее сообщение на самом деле является элементом в последнем индексе массива. Это приводит к тому, что первый оператор if вступает в силу и отображаемые элементы HTML для каждого нового сообщения, отправленного одним и тем же пользователем в тот же день (если только я не обновляю страницу, в которой все отображается правильно).

Любые обходные пути, о которых каждый может подумать?

+0

ли лучше, если вы используете значение «$ индекс» предоставленный нг-повтор объема, вместо того, чтобы пытаться для поиска индекса в массиве сообщений? –

+0

Да, это так. Я не думаю, что это повлияло на этот вопрос. – Seeeyonnn

+0

У меня нет времени на полный ответ, но в основном вам нужно назначить результат фильтра временному массиву. Посмотрите на 'ng-repeat as' –

ответ

0

Возможно, это возможно: вы можете сохранить копию $scope.messages и фильтровать этот массив, все в вашем JS. Затем скопируйте его на $scope.messages, чтобы обновить интерфейс. Что-то вроде этого:

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

Это делает его таким образом, чтобы любое изменение $scope.messages правильное изменение. Единственная плохая часть этого заключается в том, что вы сохраняете две копии сообщений в памяти

+0

Извините, нет причин копировать массив каждый раз. отредактированный – brettvd

0

См. Демонстрационную версию ниже.

вместо findig индекс вашего сообщения в контроллере здесь

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>