The view is not updated in AngularJS

JavascriptAngularjsData BindingAngular Services

Javascript Problem Overview


Updating the model property has no effect on the view when updating the model in event callback, any ideas to fix this?

This is my service:

angular.service('Channel', function() {        
	var channel = null;	
	
	return {		
		init: function(channelId, clientId) {
			var that = this;		
			
			channel = new goog.appengine.Channel(channelId);
			var socket = channel.open();
			
			socket.onmessage = function(msg) {
				var args = eval(msg.data);				
				that.publish(args[0], args[1]);
			};
		}		
	};
});

publish() function was added dynamically in the controller.

Controller:

App.Controllers.ParticipantsController = function($xhr, $channel) {
	var self = this;
	
	self.participants = [];	    
	
	// here publish function is added to service
	mediator.installTo($channel); 
	
	// subscribe was also added with publish		
	$channel.subscribe('+p', function(name) { 
		self.add(name);		
	});				    
	
	self.add = function(name) {		
		self.participants.push({ name: name });		
	}
};

App.Controllers.ParticipantsController.$inject = ['$xhr', 'Channel'];

View:

<div ng:controller="App.Controllers.ParticipantsController">      
	<ul>
		<li ng:repeat="participant in participants"><label ng:bind="participant.name"></label></li>
	</ul>
	
	<button ng:click="add('test')">add</button>
</div>

So the problem is that clicking the button updates the view properly, but when I get the message from the Channel nothings happens, even the add() function is called

Javascript Solutions


Solution 1 - Javascript

You are missing $scope.$apply().

Whenever you touch anything from outside of the Angular world, you need to call $apply, to notify Angular. That might be from:

  • xhr callback (handled by $http service)
  • setTimeout callback (handled by $defer service)
  • DOM Event callback (handled by directives)

In your case, do something like this:

// inject $rootScope and do $apply on it
angular.service('Channel', function($rootScope) {
  // ...
  return {
    init: function(channelId, clientId) {
      // ...
      socket.onmessage = function(msg) {
        $rootScope.$apply(function() {
          that.publish(args[0], args[1]);
        });
      };
    }
  };
});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionpetrov.alexView Question on Stackoverflow
Solution 1 - JavascriptVojtaView Answer on Stackoverflow