0

I'm trying to build a realtime application with AngularJS and a socket server. I try to follow John Papas Angular Styleguide

I have a factory called mainFactory:

...
socket.on('buylist', function(list) {
            buylist = list;
            $rootScope.$broadcast('buylist');
        });
...
mainFactory.getBuylist = function () {
            return buylist;
        }

For the Controller I use the ControllerAs Syntax so I build a View Model variable. homeController:

var vm = this;

$scope.$on('buylist', function(e) {
    vm.buylist = mainFactory.getBuylist();
    console.log('TO TEST WHEN THE EVENT IS FIRED!')
});

And in the View:

<li ng-repeat="listitem in home.buylist">
...
</li>

This works fine BUT the view updates 2-5 seconds after the Event is fired. But I want the view to update instantly.

I got this to work by using the $scope instead of the vm and $apply() it on the event:

$scope.$on('buylist', function(e) {
    $scope.buylist = mainFactory.getBuylist();
    $scope.$apply();
});

And in the View:

<li ng-repeat="listitem in buylist">
...
</li>

SO everything is perfectly in realtime now BUT the styleguide says that I should try to avoid using the $scope whenever it's possible and use the ViewModel ControllerAs way instead. So what I'm looking for is a way to $apply the ViewModel or some other way to update the view instantly after the event is fired.

Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
Simon Appelt
  • 305
  • 4
  • 12

1 Answers1

1

The problem is that events from your socket are not aware of AngularJS at all. Angular updates views only when changes to model are made during digest cycle. If you change model outside it, your changes will be reflected on the next digest that happens for whatever reason.

In most cases, you don't need to be aware of this provided that you "stay in Angular" all the time (for example, when you handle click events with ng-click, digest cycle is started automatically for you).

However, when you want to handle non-Angular event (i.e. socket event, or jQuery event etc), you have to care about it to make everything work. In order to make it most transparent, I would change your socket listener to:

socket.on('buylist', function(list) {
    $rootScope.$apply(function() {
        buylist = list;
        $rootScope.$broadcast('buylist');
    });
});

You may want to read more on this topic and see this similar problem.

Community
  • 1
  • 1
fracz
  • 20,536
  • 18
  • 103
  • 149