Ad

AngularJS Ng-repeat Over A Map(object) Not Updating DOM In Realtime

I have an object that is updated dynamically and populates the DOM using ng-repeat. However the DOM is not updating in the realtime, once a new value is pushed into the object even though a console.log shows that the value is added.

//appView.html
<div class="row">
        <uib-tabset type="pills" vertical="true">
            <uib-tab ng-repeat="(key, value) in channelMap">
                <uib-tab-heading>
                     <span>{{value.displayName}}</span>
                </uib-tab-heading>
                <div class="messageWrapper">
                    <div class="thread" ng-repeat="threads in value.messageThreads track by $index">
                        <span>{{threads.text}}</span>
                    </div>
                    <div class="message-area">
                        <input type="text" ng-model="messageText">
                        <button ng-click="sendMessage(key,value,messageText)">Send</button>
                    </div>
                </div>
            </uib-tab>
        </uib-tabset>   
    </div>

//Controller.js

$scope.channelMap = {};
subscriptionCallback = function(data)
        {
            var messageFromServer = JSON.parse(data.body);
            if (messageFromServer.isSuccess) {
                var messageObj = messageFromServer.data;
                console.log(messageObj);
                if (messageObj.messageType === "CREATE_CHANNEL") {
                    // Subscribing to private channel
                    subscribeToChannel(messageObj.text, subscriptionCallback);
                    //Put it in channelsMap with reciever id as key
                    var threadObj = {};
                    var displayName = "";
                    if($scope.user.id == messageObj.recieverId){
                        displayName = messageObj.senderName + " (" + messageObj.usernameSender + " )";
                    }
                    else{
                        displayName = messageObj.recieverName + " (" + messageObj.usernameReciever + " )";
                    }
                    threadObj.displayName = displayName;
                    threadObj.channenId = messageObj.text;
                    threadObj.messageThreads = [];
                    $scope.channelMap[messageObj.recieverId] = threadObj;
                    console.log($scope.channelMap);
                }
                else{
                    var msg = {};
                    msg.text = messageObj.text;
                    msg.senderId = messageObj.senderId;
                    msg.recieverId = messageObj.recieverId;
                    $scope.channelMap[messageObj.recieverId].messageThreads.push(msg);
                    console.log($scope.channelMap[messageObj.recieverId].messageThreads);
                }
            }
        }

The function subscriptionCallback is called once a response is received from server and is responsible for populating data in $scope.channelMap which it does successfully if I examine console.log, however if I perform any action on DOM, the DOM is updated. I also tried to use controller as . (dot) syntax, however it rendered the ng-repeat part blank even after I perform any action on DOM.

Ad

Answer

To judge from your comment

Subscription callback is called once the server sent a message to client, this snippet is a part of web socket based program

As the subscriptionCallback is called from outside of angular control, any changes to the controller scope will not be synced to the view as angular don't know when changes have been made.

To solve this, wrapp your scope changes in $scope.$apply(fn);

$scope.channelMap = {};
subscriptionCallback = function(data)
{
    $scope.$apply(function() {
        var messageFromServer = JSON.parse(data.body);
        if (messageFromServer.isSuccess) {
            var messageObj = messageFromServer.data;
            console.log(messageObj);
            if (messageObj.messageType === "CREATE_CHANNEL") {
                // Subscribing to private channel
                subscribeToChannel(messageObj.text, subscriptionCallback);
                //Put it in channelsMap with reciever id as key
                var threadObj = {};
                var displayName = "";
                if($scope.user.id == messageObj.recieverId){
                    displayName = messageObj.senderName + " (" + messageObj.usernameSender + " )";
                }
                else{
                    displayName = messageObj.recieverName + " (" + messageObj.usernameReciever + " )";
                }
                threadObj.displayName = displayName;
                threadObj.channenId = messageObj.text;
                threadObj.messageThreads = [];
                $scope.channelMap[messageObj.recieverId] = threadObj;
                console.log($scope.channelMap);
            }
            else{
                var msg = {};
                msg.text = messageObj.text;
                msg.senderId = messageObj.senderId;
                msg.recieverId = messageObj.recieverId;
                $scope.channelMap[messageObj.recieverId].messageThreads.push(msg);
                console.log($scope.channelMap[messageObj.recieverId].messageThreads);
            }
        }
    });
}
Ad
source: stackoverflow.com
Ad