A few days back, I blogged on using SignalR and Angular JS together and on Implementing SignalR stock ticker sample using Angular JS(Part 1 and Part 2). In those posts, I have used the traditional call-back model to call the functions defined in controller to modify data whenever an update is received from the server.
One of the readers sent me feedback saying that we have a better way to use SignalR and Angular JS together. The way to go is using event methods defined on $rootscope object. This approach is based on publishing and subscribing events. As events can be published from anywhere and subscribed from anywhere, the source and destination will remain completely unaware of each other. Both of them have to depend on just one object, $rootScope.
Official documentation on scope contains details on each method defined on $rootScope. We will be using the following methods for publishing and subscribing the events:
- $emit(name, args): Publishes an event with specified name with given arguments
- $on(name, listener): Subscribes to an event with specified name. Listener is a function containing logic to be executed once the event has occurred
To manage SignalR’s client functionality, it is better to create a service, as services are singletons. There will be only one instance of the service in entire application. This behaviour of services makes it possible to have multiple SignalR client pages in the applications and they can be kept in sync without putting any extra amount of effort.
Let’s modify the example discussed in the post titled Hooking up ASP.NET SignalR with Angular JS to use event model. Server hub, references and structure of the HTML page remains the same as past. The only components to be modified are Controller and Service.
Service carries the responsibility to initialize a connection to the hub and call the SignalR’s server methods. Once a response is received from the server, we will broadcast an event from the service with data received.
01.
app.service(
'signalRSvc'
,
function
($, $rootScope) {
02.
var
proxy =
null
;
03.
04.
var
initialize =
function
() {
05.
//Getting the connection object
06.
connection = $.hubConnection();
07.
08.
//Creating proxy
09.
this
.proxy = connection.createHubProxy(
'helloWorldHub'
);
10.
11.
//Starting connection
12.
connection.start();
13.
14.
//Publishing an event when server pushes a greeting message
15.
this
.proxy.on(
'acceptGreet'
,
function
(message) {
16.
$rootScope.$emit(
"acceptGreet"
,message);
17.
});
18.
};
19.
20.
var
sendRequest =
function
() {
21.
//Invoking greetAll method defined in hub
22.
this
.proxy.invoke(
'greetAll'
);
23.
};
24.
25.
return
{
26.
initialize: initialize,
27.
sendRequest: sendRequest
28.
};
29.
});
To keep the things simple, I kept names of the server hub event and event rose using $emit the same. The names can be different. Let’s modify the controller to have a listener to the event raised by the service. Following is the implementation of the controller:
01.
function
SignalRAngularCtrl($scope, signalRSvc, $rootScope) {
02.
$scope.text =
""
;
03.
04.
$scope.greetAll =
function
() {
05.
signalRSvc.sendRequest();
06.
}
07.
08.
updateGreetingMessage =
function
(text) {
09.
$scope.text = text;
10.
}
11.
12.
signalRSvc.initialize();
13.
14.
//Updating greeting message after receiving a message through the event
15.
16.
$scope.$parent.$on(
"acceptGreet"
,
function
(e,message) {
17.
$scope.$apply(
function
() {
18.
updateGreetingMessage(message)
19.
});
20.
});
21.
}
Now open the modified page on multiple browsers and click the Greeting button randomly from all browsers. Messages printed on all browsers should be updated whenever the button is clicked. This behaviour is same as it was earlier. We just adopted a better approach to make it work.
Happy coding!
Happy coding!
No comments:
Post a Comment