2014-09-11 61 views
4

我使用SignalR爲我的應用程序,它與簡單的JavaScript工作,但現在我試圖重寫它與角包裝https://github.com/JustMaier/angular-signalr-hub,但我遇到了錯誤,同時試圖連接到我的集線器:SignalR和AngularJS

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()"> 

這裏是我的代碼:

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; 
}]) 

有誰與熟嗎?

+0

以及錯誤信息SA ys叫'開始'。你嘗試過嗎? – 2014-09-11 12:31:42

+0

此包裝(角服務)的想法https://github.com/JustMaier/angular-signalr-hub,正如我undersand,是控制集線器起始和轂聽衆和在客戶端方法簡化declaretion。 – 2014-09-11 12:36:41

+0

這不是ralated到signalr但爲什麼你使用jQuery模式,嘗試使用angularJS指令做這件事http://angular-ui.github.io/bootstrap/ – 2014-09-11 13:38:25

回答

0

根據SignalR-Hub項目的源代碼,創建新集線器時應該啓動連接。您是否檢查了瀏覽器控制檯可能的連接錯誤?

該庫還提供了訪問start()的承諾。附上自己的承諾,檢查集線器是否已成功連接到服務器。示例:

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

承諾對象是對信號啓動方法的承諾的訪問。

3

您必須遇到異步問題。當您調用方法時,連接尚未打開。

嘗試修復您的signalr-hub.js,我想我們應該使用不同的承諾停止和開始。

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

和:

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); 
      } 
     }; 
}); 

或者:

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到集線器。這將返回一個角色承諾,而不是jQuery的承諾。因此,角度意識到事件,我們不需要在回調中使用$rootScope.$apply()

和:

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

這是討論 [here]

vmlf01的評論是:

創建輪轂具有對應於返回值從」。開始了 「.promise」 屬性( )」。我使用初始化一個承諾,在完成的()回調解析它在我的連接時建立連接,就像這樣:

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

這就像我在答覆中指出了同樣的問題。只是解決方案不同。 – 2014-10-20 13:00:36

0

確保安裝和參考jquery.signalR-2.1.2。js文件

0

包裝SignalR時AngularJS使用的是這是什麼幫助我:

** 轉換所有SignalR(jQuery的)承諾角$ Q承諾。 **

好處:

  1. 所有來電者有一個一致的承諾接口(例如finally()而不是always()

  2. 承諾是在錯誤(無需try ... catch拒絕),例如如果連接未啓動,按您的問題

  3. 角的$digest週期被激發

考慮到這一點,你可以在你的Hub.invoke方法改成這樣:

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 
    } 

Hub.connect

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