SignalR and AngularJS

I use SignalR for my application and it works with simple javascript, but now I am trying to rewrite it with angular -wrapper https://github.com/JustMaier/angular-signalr-hub , but I encountered an error while trying to connect to to my hub:

Error: SignalR: Connection must be started before data can be sent. Call .start() before .send()
at Object.signalR.fn.signalR.send (http://localhost:47124/Scripts/jquery.signalR-2.1.1.js:789:23)
at Object.hubProxy.fn.hubProxy.invoke (http://localhost:47124/Scripts/jquery.signalR-2.1.1.js:2609:24)
at Hub.invoke (http://localhost:47124/Scripts/angular-signalr-hub.js:30:28)
at Hub.(anonymous function) [as loadRecentPhotos] (http://localhost:47124/Scripts/angular-signalr-hub.js:49:24)
at Object.PhotoMarkers.load (http://localhost:47124/Scripts/AngApp.js:47:17)
at http://localhost:47124/Scripts/angular.js:10836:21
at Scope.$eval (http://localhost:47124/Scripts/angular.js:12673:28)
at pre (http://localhost:47124/Scripts/angular.js:19943:15)
at nodeLinkFn (http://localhost:47124/Scripts/angular.js:6684:13)
at compositeLinkFn (http://localhost:47124/Scripts/angular.js:6098:13) <div class="modal-body" ng-init="markers.load()"> 

Here is my code:

angular.module('FlickrMaps', ['SignalR'])
.factory('PhotoMarkers', ['$rootScope', 'Hub', function ($rootScope, Hub) {
    var PhotoMarkers = this;

    //Hub setup
    var hub = new Hub('photos', {
        listeners: {
            'addTotalPhotosCount': function (total) {
                PhotoMarkers.totalCount = total;
                $rootScope.$apply();
            },

            'initPhotoMarker': function (photo) {
                var photolocation = new window.google.maps.LatLng(photo.Latitude, photo.Longitude);
                PhotoMarkers.all.push(new window.google.maps.Marker({
                    position: photolocation,
                    title: photo.Title,
                    photoThumb: photo.PhotoThumbScr,
                    photoOriginal: photo.PhotoOriginalScr
                }));
                $rootScope.$apply();
            },

            'photosProcessed': function () {
                PhotoMarkers.processedPhotosCount++;
                $rootScope.$apply();
            },
        },
        methods: ['loadRecentPhotos'],
        errorHandler: function (error) {
            console.error(error);
        }
    });

    //Variables
    PhotoMarkers.all = [];
    PhotoMarkers.processedPhotosCount = 0;
    PhotoMarkers.totalCount = 0;

    //Methods
    PhotoMarkers.load = function () {
        $('#myModal').modal({
            backdrop: 'static',
            keyboard: false
        });
        hub.loadRecentPhotos();
    };

    return PhotoMarkers;
}])
.controller('MapController', ['$scope', 'PhotoMarkers', function ($scope, PhotoMarkers) {
$scope.markers = PhotoMarkers;
}])

Anyone familiar with this?

+4
source share
6 answers

You should run into asynch problems. When you call the method, the connection is not yet open.

Try installing signalr-hub.js, I think we should use different promises to stop and start.

    Hub.disconnect = function () {
        Hub.stopPromise = Hub.connection.stop();
    };
    Hub.connect = function () {
        Hub.startPromise = Hub.connection.start();
    };

and

angular.forEach(options.methods, function (method) {
        Hub[method] = function () {
            var args = $.makeArray(arguments);
            args.unshift(method);
            return Hub.startPromise.then(function(){
                //invoke method only after startPromise is resolved
                 return Hub.invoke.apply(Hub, args);
            }
        };
});

Or:

angular.forEach(options.methods, function (method) {
        Hub[method] = function () {
            var args = $.makeArray(arguments);
            args.unshift(method);

            var def = $q.def();
            Hub.startPromise.then(function(){
                    //invoke method only after startPromise is resolved
                  Hub.invoke.apply(Hub, args).done(function(){
                         def.resolve();
                  });
            }

            return def.promise;
        };
 });

$q . angular jQuery. angular , $rootScope.$apply() .

//Adding additional property of promise allows to access it in rest of the application.
   Hub.startPromise = Hub.connection.start();
+3

SignalR-Hub, . ?

start(). , , . :

hub.promise
    .done(function(){ console.log('connection established'); })
    .fail(function(){ console.log('connection error'); });

- - signalR.

0

[]

vmlf01:

".promise", ".start()". , done(), , :

    function initialize() {
        var deferred = $q.defer();

        foldersHubConnection = new Hub('Folders', {
            listeners: folderHubListeners(),
            methods: folderServerCalls(),
            rootPath: config.eventsServerEndpoint
        });

        foldersHubConnection.promise.done(function () {
            deferred.resolve(foldersHubClient);
        });

        foldersHubConnection.promise.fail(function (error) {
            deferred.reject(new Error("Error connecting to Events Server: " + error));
        });

        return deferred.promise;
    }
0

, jquery.signalR-2.1.2.js

0

SignalR AngularJS:

** SignalR (jQuery) promises Angular $q promises. **

:

  • (, finally(), always())

  • A promise is rejected on error (no need for try... catch), for example. if the connection is not started, according to your question

  • Angular $digestloop starts

With this in mind, you can change your method Hub.invoketo this:

Hub.invoke = function(method, args) {
    try {
       var jQueryPromise = Hub.proxy.invoke.apply(Hub.proxy, arguments);

        return $q.when(jQueryPromise);    // <- return as $q promise

    } catch(e) {
        return $q.reject(e);              // <- exception to $q.reject
    }

and Hub.connectup

Hub.connect = function (queryParams) {
    ...
    return $q.when(Hub.connection.start(startOptions));  // <- return $q promise
};
0
source

All Articles