8

I'm trying to change my angular model after a websocket push from the server. How is it possible to change values like $scope.contacts each time the server serves new data..?

I'm not sure if it is possible by using $apply. I know that I can access the DOM element retrieve the scope and then change the values, but there should be a better solution!

I'm really interested in a solution to update the angular model from outside without creating angular modules since I'm using relative data sources that emit change events. Is there no simple way to do that like in Backbone.js where you can say:

var book = new Backbone.Model({ title: 'value' });
book.set("title", "A Scandal in Bohemia");

What I want in angularjs is something like:

function MyController($scope) {
    $scope.contacts = [];
}

datasource changed -> function () {
    MyController.set('contacts', 'value'); // change angular scope property
}
T J
  • 42,762
  • 13
  • 83
  • 138
Pascal Bayer
  • 2,615
  • 8
  • 33
  • 51

3 Answers3

11

Look at socket.io angular service:

angular.module('app')
  .factory('socket', ['$rootScope', function ($rootScope) {

    var socket = io.connect();

    return {
      on: function (eventName, callback) {
        socket.on(eventName, function () {  
          var args = arguments;
          $rootScope.$apply(function () {
            callback.apply(socket, args);
          });
        });
      },
      emit: function (eventName, data, callback) {
        socket.emit(eventName, data, function () {
          var args = arguments;
          $rootScope.$apply(function () {
            if (callback) {
              callback.apply(socket, args);
            }
          });
        })
      }
    };

  }]);

and controller using it:

angular.module('app')
  .controller('Controller', ['$scope', 'socket', function ($scope, socket) {

    socket.emit('register')

    socket.on('register', function (data) {
        $scope.data = data;
    });

}]);
Maxim Grach
  • 4,300
  • 2
  • 20
  • 19
  • That's a really nice example but it will not work in my case, since I'm synchronizing data with Collections on the client and these Collections emit the change events. I can change to code to get it working with your suggestion, but what I really want to have is `scope.contacts = db.collection('contacts').find('favorites');` and set the angular model property every time my collection is updated and then call this code. – Pascal Bayer Feb 05 '13 at 09:15
  • Which db you are using on client? Does `find()` have callback function? Could you show full source of client? – Maxim Grach Feb 05 '13 at 15:29
2

just do it like below

 socket.onmessage = function (event) {
     scope.$apply(function(){
       // modify scope values here 
     }
    };
Ajay Beniwal
  • 18,857
  • 9
  • 81
  • 99
  • Correct me if I'm wrong but when I have retrieved my scope I can simply change values by `scope.variable = 'value'`. My question is about how to retrieve the scope I want to change on a simple way. – Pascal Bayer Feb 05 '13 at 08:45
  • have u created a angular service for making websocket request – Ajay Beniwal Feb 05 '13 at 09:01
  • +1 Great find @Ajaybeniwal - I've combined your code above with the ability to retrieve the scope of an element within your own JS and put it in a new answer below :) – Jimbo Oct 24 '13 at 16:30
1

Well, the marked answer is certainly not a "simple way" as requested by OP. Here's a much simpler solution.

Retrieve the scope wherever you want in your own JavaScript code:

var scope = angular.element($("#elementID")).scope();

Change a value in your Angular $scope variable, but from your external JavaScript:

scope.$apply(function() {
    scope.yourArrayForExample.push({name: 'New, external value'});
});

Here's a JSFiddle.

Jimbo
  • 25,790
  • 15
  • 86
  • 131