3

1.- It's a simple ng-route setup, I have 3 buttons, each button navigates to a new path.

2.- I have a parent controller and a child controller for ng-view

3.- For ng-view I have a template with a span bound to property subCtrl.id and another span bound to 'subCtrl.something' with an initial value of something.id=1 and something.name='blondie'

4.-If I call the signalR method through Fiddler and I'm at the intitial route everything works fine: SignalR updates the view with 'Angel Eyes'

PROBLEM: BUT If I change the route and navigate to ctrl.optionSelected(2) or ctrl.optionSelected(3) and call SignalR method through FIDDLER, the client receives it and console prints 'Angel eyes', BUT the view is not updated!

HTML

<div ng-app="app">
<div ng-controller="mainCtrl as ctrl">
    <button ng-click="ctrl.optionSelected(1)">1</button>
    <button ng-click="ctrl.optionSelected(2)">2</button>
    <button ng-click="ctrl.optionSelected(3)">3</button>
    <div ng-view></div>
</div>

<script type="text/javascript" src="~/Scripts/jquery-2.2.3.min.js"></script>
<script type="text/javascript" src="~/Scripts/angular.min.js"></script>
<script type="text/javascript" src="~/Scripts/angular-animate.min.js"></script>
<script type="text/javascript" src="~/Scripts/angular-route.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.signalR-2.2.0.min.js"></script>
<script type="text/javascript" src="~/signalr/hubs"></script>
<script type="text/javascript" src="~/Scripts/app.js"></script>

JAVASCRIPT

var app = angular.module('app', ['ngRoute']);
app.config(['$routeProvider', function ($routeProvider) {
    $routeProvider.when('/:id', {
        templateUrl: '/Templates/template.html',
        controller: 'subCtrl',
        controllerAs: 'sctrl'
    });
}]);

app.controller('mainCtrl', ['$location', function ($location) {
   var self = this;
   self.optionSelected = function (option) {
      $location.path("/" + option);
   };

}]);

app.controller('subCtrl', ['$routeParams', '$scope', function ($routeParams, $scope) {
    var self = this;
    self.something= {};
    self.something.id = $routeParams.id;
    self.something.name = 'Blondie';

    self.hub = $.connection.AppHub;

    /*****HERE IS THE PROBLEM*************/
    self.hub.client.Hello = function () {
         console.log("Angel eyes");
         self.something.name= 'Angel eyes';
         $scope.$apply();
         };
    /*************************************/
$.connection.hub.start().done(function () {
    console.log('SignalR connection started');
    });
}]);

Templates/Template.html

<span ng-bind="sctrl.something.id"></span>
<span ng-bind="sctrl.something.name"></span>

SIGNAL R Method:

    [HttpGet]
    [Route("api/app/GetSignalRTest")]
    public IHttpActionResult GetSignalRTest()
    {
     var context = GlobalHost.ConnectionManager.GetHubContext<AppHub>();
     context.Clients.All.hello();  
     return Ok();
    }

The code and explanation seems to be too long but it's actually very simple, please watch the following gifs

Works with initial route:

enter image description here

Does not work after changing view:

enter image description here

What am I doing wrong here?

The One
  • 4,560
  • 5
  • 36
  • 52

3 Answers3

3

Thanks to Leandro Tutini who answered this on es.stackoverflow

Only the first controller is being attached to the SignalR event that's why the second controller is not working.

You can move the SignalR definition to the base controller which is going to catch the events and propagate them to the child controller

app.controller('mainCtrl', ['$location', '$scope', '$rootScope', function ($location, $scope, $rootScope) {

var self = this;
self.optionSelected = function (option) {
    $location.path("/" + option);
}
self.hub = $.connection.AppHub;


self.hub.client.Hello = function () {
console.log("Hello");
$rootScope.$broadcast('UpdateName', 'Angel eyes');
};

$.connection.hub.start().done(function () {
    console.log('SignalR connection started');
    });
}]);


app.controller('subCtrl', ['$routeParams', '$scope', function ($routeParams, $scope, $rootScope) {
var self = this;
self.something= {};
self.something.id = $routeParams.id;
self.something.name = 'Blondie';

$scope.$on('UpdateName', function(name){ 
    self.something.name = name;
    $rootScope.$apply();
    });

}]);
Community
  • 1
  • 1
The One
  • 4,560
  • 5
  • 36
  • 52
0

This can be done using $timeout directive. Fire the angular events again after all the hub changes are done/ This can be done using $timeout directive. Fire the angular events again after all the hub changes are done/

  • AngularJS and SignalR are two libries. once the changes happens on signalR hub end it will not automatically pick by the angular. Angular does not know hub updates. – user3484630 Apr 26 '16 at 05:30
  • We must need to fire all the angularjs events after the hub changes done – user3484630 Apr 26 '16 at 05:31
0

Yes, I can confirm that SignalR stuff should be on the main ng-controller.

Here in my Angular SPA WebAPI project, I couldn't make my collection get updated (view - ngRepeat) whenever I route to another page and come back. It worked only when I moved from msgsCtrl to rootCtrl, and making use of $rootScope.

Marcelo Santos
  • 128
  • 1
  • 4