Несколько дней назад я написал в блоге об совместном использовании SignalR и Angular JS и о внедрении образца биржевого тикера SignalR с использованием Angular JS ( часть 1 и часть 2 ). В этих сообщениях я использовал традиционную модель обратного вызова для вызова функций, определенных в контроллере, для изменения данных при получении обновления от сервера.
Один из читателей прислал мне отзыв о том, что у нас есть лучший способ использовать SignalR и Angular JS вместе. Для этого нужно использовать методы событий, определенные для объекта $ rootscope., Этот подход основан на публикации и подписке на события. Поскольку события могут быть опубликованы из любого места и подписаны из любого места, источник и место назначения будут совершенно не знать друг друга. Оба они должны зависеть только от одного объекта, $ rootScope.
Официальная документация по области действия содержит подробную информацию о каждом методе, определенном в $ rootScope. Мы будем использовать следующие методы для публикации и подписки на события:
- $ emit (name, args): публикует событие с указанным именем с заданными аргументами
- $ on (name, listener): подписывается на событие с указанным именем. Слушатель — это функция, содержащая логику, которая должна быть выполнена после того, как событие произошло
Чтобы управлять функциональностью клиента SignalR, лучше создать сервис, так как сервисы являются единичными. Во всем приложении будет только один экземпляр службы. Такое поведение сервисов позволяет иметь несколько клиентских страниц SignalR в приложениях, и их можно синхронизировать без дополнительных усилий.
Давайте изменим пример, рассмотренный в посте « Подключение ASP.NET SignalR к Angular JS», чтобы использовать модель событий. Серверный хаб, ссылки и структура HTML-страницы остаются прежними. Единственные компоненты, которые должны быть изменены, это контроллер и сервис.
Сервис несет ответственность за инициализацию соединения с концентратором и вызов метода сервера SignalR. Как только ответ получен от сервера, мы будем транслировать событие от службы с полученными данными.
app.service('signalRSvc', function ($, $rootScope) { var proxy = null; var initialize = function () { //Getting the connection object connection = $.hubConnection(); //Creating proxy this.proxy = connection.createHubProxy('helloWorldHub'); //Starting connection connection.start(); //Publishing an event when server pushes a greeting message this.proxy.on('acceptGreet', function (message) { $rootScope.$emit("acceptGreet",message); }); }; var sendRequest = function () { //Invoking greetAll method defined in hub this.proxy.invoke('greetAll'); }; return { initialize: initialize, sendRequest: sendRequest }; });
Чтобы упростить задачу, я сохранил имена событий сервера-концентратора и события с помощью $ emit. Имена могут быть разными. Давайте изменим контроллер, чтобы прослушиватель события вызывался службой. Ниже приведена реализация контроллера:
function SignalRAngularCtrl($scope, signalRSvc, $rootScope) { $scope.text = ""; $scope.greetAll = function () { signalRSvc.sendRequest(); } updateGreetingMessage = function (text) { $scope.text = text; } signalRSvc.initialize(); //Updating greeting message after receiving a message through the event $scope.$parent.$on("acceptGreet", function (e,message) { $scope.$apply(function () { updateGreetingMessage(message) }); }); }
Теперь откройте измененную страницу в нескольких браузерах и нажмите кнопку Приветствие в произвольном порядке во всех браузерах. Сообщения, напечатанные во всех браузерах, должны обновляться при каждом нажатии кнопки. Это поведение такое же, как было раньше. Мы просто приняли лучший подход, чтобы заставить его работать.
Удачного кодирования!