I've created Angular application based on routes. Without using the routes, the Signalr works fine, but when I work with routes, the Signalr works just in one way - from client side to server.
<html ng-app="SignalR">
<head>
//Scripts
<script src="~/signalr/hubs"></script>
</head>
<body>
<a href="#/Today">Today</a>
<a href="#/History">History</a>
<div ng-view>
</div>
<script type="text/javascript">
var hubConnetion = undefined;
hubConnetion = $.connection.hubs;
$.connection.hub.start();
var SignalRControllers = angular.module('SignalRControllers', []);
var SignalRApp = angular.module('SignalR', ['ngRoute', 'SignalRControllers']);
SignalRApp.config(['$routeProvider',
function ($routeProvider) {
$routeProvider.
when('/Today', {
templateUrl: '@Url.Action("Today","Home")'
}).
when('/History', {
templateUrl: '@Url.Action("History", "Home")'
})
}]);
</script>
<script src="~/AngularJs/TodayController.js"></script>
</body>
</html>
TodayController.js
SignalRControllers.controller('TodayController', ['$scope', '$http',
function ($scope, $http) {
$scope.sendTask = function () {
hubConnetion.server.sendTask($("#taskName").val());//works
}
$scope.Task = "task1";
hubConnetion.client.getTask= function (Task) {//never invoked
$scope.Task = Task;
}
}]);
Today.html
<div ng-controller="TodayController">
<div>{{Task}}</div>
<input id="taskName" type="text" />
<div ng-click="sendTask()">SendTask</div>
</div>
Hubs.cs
public class Hubs: Hub
{
public void SendTask(string Name)
{
Clients.All.GetTask(Name);
}
}
I'm not sure, but I think that because the hubConnetion variable is wrapped inside the controller, signlarR couldn't find it. Is there any angular magic that can solve this ?
I'm also fairly new to SignalR (and first time user of Angular) so I'v recreated (and simplified) the project in ASP.NET MVC 4 (SignalR 2.2) to nail the problem . And I think there is more then one...
1) SignalR is using JQuery. In jQuery (and almost any other JS framework) its relly better to execute your code after 'document ready' event. So I wrapped SignalR setup in jQuery document ready handler (see code below). Additionally I removed
hubConnetion
global variable because global variables are bad + after wrapping in jQuery document ready handler, variable is local to that handler and not accessible in controller code anyway...2) Main problem IMHO is this (part of SignalR client API):
Your event handler is setup in controller factory method which is called much later then connection
start()
method. Try to add temporary handler before callingstart()
like this:$.connection.tasklistHub.client.getTask = function () { };
3) To be sure the problem is in SignalR and not Angular, i'v turned on both server and client side tracing. After all the changes above, event from server was successfully received on client:
SignalR: Triggering client hub event 'getTask' on hub 'TasklistHub'
But Angular failed to update div with data received. Solution is to use
$rootScope.$apply
function mentioned in this article about using SignalR and Angular together. Now everything works as expected. See full code below.Sidenote: I understand this is just sample code. In any real world project I would consider wrapping SignalR hubs on client in some kind of service like in article mentioned above or using this library (looks very elegant)
I also take back my previous answer regarding the client side handler name as according to the same document, client side method name matching is case-insensitive...
Index.cshtml
TodayController.js
Your Solution is perfect and for those that face this problem even after your lecture, there is a simple solution to get response from server to client in every part of app:
And in your view u are able to use 'messages' array everywhere:
My issue