title: How do I handle a SignalR event from within an Angular service?
body: <p>I have an Angular app that has a service wrapping up SignalR interaction. I can send data to the server from both the page and within an Angular service but can only handle events from the page (events in the service never fire).</p>
  
  <p>For some context, this is a test app for having video controls in a different window to the video that is playing.</p>
  
  <p><strong>SignalR Hub code</strong></p>
  
  <pre><code>public class VideoHub : Hub
  {
      public void SetPlaybackStatus(string status)
      {
          Clients.All.statusChanged(status);
      }
  }
  </code></pre>
  
  <p><strong>Angular Controller</strong></p>
  
  <pre><code>commsTest.controller("videoController", [
      '$scope', 'signalRService',
      function ($scope, signalRService) {
  
          $scope.playbackStatus = "No Status";
  
          signalRService.onStatusChanged(function (status) {
              console.log("Callback status", status);
              $scope.playbackStatus = status;
          });
      }
  ]);
  </code></pre>
  
  <p><strong>SignalR Angular Service</strong></p>
  
  <pre><code>commsTest.service('signalRService', [
      '$', function ($) {
  
          var proxy,
              initialized = false,
              statusChangeCallbacks = [];
  
          var initialize = function (callback) {
  
              // Get the connection object
              var connection = $.hubConnection();
  
              // Create proxy
              proxy = connection.createHubProxy('videoHub');
  
              // Start connection
              connection.start().done(function () {
                  initialized = true;
                  console.log("Connected");
                  callback();
              });
  
              // This bit here never fires
              proxy.on('statusChanged', function (status) {
                  console.log("Caught from service.", status);
                  callStatusChangedCallbacks(status);
              });
          };
  
          var setPlaybackStatus = function (status) {
              if (!initialized) {
                  initialize(function() {
                      setPlaybackStatus(status);
                  });
              } else {
                  // This bit works as expected
                  proxy.invoke('setPlaybackStatus', status);
              }
          };
  
          var onStatusChanged = function (callback) {
              if (callback) {
                  statusChangeCallbacks.push(callback);
              }
          };
  
          function callStatusChangedCallbacks(status) {
              for (var i = statusChangeCallbacks.length - 1; i &gt;= 0; i--) {
                  statusChangeCallbacks[i](status);
              }
          }
  
          return {
              onStatusChanged: onStatusChanged,
              setPlaybackStatus: setPlaybackStatus
          };
      }
  ]);
  </code></pre>
  
  <p>The event handler (marked above) never fires within the service. I have this code directly on the page:</p>
  
  <pre><code>$(function() {
      // Gett the connection object
      var connection = $.hubConnection();
  
      // Create proxy
      var proxy = connection.createHubProxy('videoHub');
  
      // Start connection
      connection.start();
  
      // This gets called as expected
      proxy.on('statusChanged', function (status) {
          console.log("Caught in page.", status);
      });
  })
  </code></pre>
  
  <p>This fires as expected when the server code emits the update.</p>
  
  <p>I've also tried using the direct methods on the JS side instead of a proxy but I get the same result.</p>
  
  <p>i.e.</p>
  
  <pre><code>var videoHub = $.connection.videoHub;
  videoHub.client.statusChanged = function (status) {
      console.log("Callback within service");
      callStatusChangedCallbacks(status);
  };
  </code></pre>
  
  <p>Is there something going on with the encapsulation of the objects within Angular that stops the JS in there picking up the event?</p>
  
  <p>Just for completion's sake, I'm passing in jQuery as such:</p>
  
  <pre><code>var commsTest = angular.module('commsTest', ['ngRoute'])
      .config(['$locationProvider', '$routeProvider', '$httpProvider', function ($locationProvider, $routeProvider, $httpProvider) {
      delete $httpProvider.defaults.headers.common['X-Requested-With'];
  
      // Routes stuff
  }]);
  
  commsTest.value('$', $);
  </code></pre>
  
  <p>Any suggestions very much welcome.</p>