1

I'm using AngularJS 1.2.0 to create a simple messaging app over a websocket. The HTML is using ng-repeat on a list to generate the total output (an array of messages I'm inputting). I'm using a factory to host 'private' data and methods and exposing only the view model and functions to manipulate the data in the controller:

<form class="form-search">
    <input type="text" ng-model="model.input" class="input-large"
           placeholder="Enter your message:">
    <button type="submit" class="btn" ng-click="sendMessage()">Send</button>
</form>

<ul>
    <li ng-repeat="message in model.output track by $index" ng-bind="message"></li>
</ul>


application.controller('MessageCtrl', ['$scope', 'MessageService', function($scope, Service) {
    $scope['model'] = Service.view;

    $scope.sendMessage = function() {
        Service.sendMessage();
    };

    $scope.$watchCollection(function() {
        return Service['view'];
    }, function(data) {
        $scope['model'] = data;
    });
}])
.factory('MessageService', function('Restangular') {
    var Service = {
        // other private properties
        view: {
            input: null,
            output: []
        }
    };

    openConnection();

    function openConnection() {
        // retrieves websocket URL over Restangular
        // opens websocket
    }

    function sendMessage() {

        // sends input over socket
        // promises are resolved and unshifted onto Service['view']['output'].
    }

    return {
        view: Service['view'],
        sendMessage: function() {
            sendMessage();    
        }
    }
}); 

Everything is working properly except that the DOM's ng-repeat is not updating when the output array in Service['view'] gets a new message. I've tried using $watchCollection as a solution in this thread: AngularJS : The correct way of binding to a service properties, but this doesn't work either. The only way I can get the DOM to re-render is by forcing it to re-render by changing the input text or triggering hover states in CSS.

Given this setup, what would be the best way to trigger a digest so the DOM renders as soon as a promise is resolved with new message data and unshifted onto the output array? I want to avoid using $rootScope and firing events as that can get very unclean when other Controllers use the factory.

Community
  • 1
  • 1
SirTophamHatt
  • 1,581
  • 17
  • 23

1 Answers1

1

In the Service, I've added the $rootScope dependency and used $rootScope.$apply() where the promises are being resolved and updating the model.

$rootScope.$apply(function() {
    Service['view']['output'].unshift(newMessage)
});

This seems to solve the digest issue although I'm not sure what the side effects are.

SirTophamHatt
  • 1,581
  • 17
  • 23