2016-06-13 10 views
1

角度アプリにUI-Routerを使用しています。私は$http非同期呼び出しを介して引っ張っているデータを持っています。これは、ソートの接続オブジェクトを作成するために使用されます。私の目標は、このオブジェクトを作成し、それをシングルトンとして利用できるようにすることです。それが起こる可能性はまれですが、サービス内のsocketプロパティが非同期に割り当てられているタイミングの問題を避けることを検討しています。ルータ内の別の状態が別の接続オブジェクトを取得または作成したい場合は、シングルトンを介して行い、別の接続を作成する代わりに同じ接続を使用することができます。UI-Routerのための角度サービス非同期シングルトン

以下は、私が働くことを試みているいくつかのコードのスケルトンです。状態のresolveで何かができるかどうか分かりません。

どのようにこれを行うことができますか?

var myapp = angular.module('me', ['ui.router']) 
.service('connectionService', ['$http', function($http) { 
    var socket; 

    // Somehow call and store result of $http in a singleton 
    // Would the $http.get get put in some kind of function? If so, how should it get called 
    // and returned so that a user of the service can get the 'socket' object synchronously? 
     $http.get("something/that/returns/data") 
      .success(function (result) { 
       this.socket= createConnection(result.data); 
      }) 
      .error(function (err) { 
       //handle error 
      }) 

    var getSocket= function() { 
     if (!this.socket) { 
      return createNewSocket(); 
     } else { 
      return this.socket; 
     } 
    } 
}]) 

myapp.config(function($stateProvider, $urlRouterProvider) { 
    $urlRouterProvider.otherwise("home"); 

    $stateProvider 
     .state('home', { 
      url: "/home", 
      templateUrl: "home.html", 
      resolve: { 
       socket: // ??? Can something be done here ??? 
      }, 
      controller: function(socket) { 
       // I can haz socket? 
      } 
     }) 
     .state('nextState', { 
      url: "/next", 
      templateUrl: "next.html", 
      resolve: { 
       socket: // Should be the same socket object as from the home state 
      }, 
      controller: function(socket) { 
       // I can haz same socket? 
      } 
     }) 
}) 

更新

より良い問題を説明しようとする過程で、私は元のコードを数回に変更されました。人々は私が持っていた明確な誤りを訂正したまま残しています。私は上記のコードを本来のやり方に戻し、以下に新しいコードを追加しました。私がまだ抱えている問題は、ui-router状態のresolveがコントローラに入る前に解決していないということです。だから、解決しようとしているsocketオブジェクトのemit()を呼び出すと、「プロパティを読み取ることができません」というメッセージが表示されます。私はまだsocketオブジェクトが状態間で同じオブジェクトであることを望んでいます。私は正しい方向に私を助けるために他の提案やコメントを感謝します。ソリューション作業

var myapp = angular.module('me', ['ui.router']) 
.service('connectionService', ['$http', function($http) { 
    var socket; 

    // Somehow call and store result of $http in a singleton 
    // Would the $http.get get put in some kind of function? If so, how should it get called 
    // and returned so that a user of the service can get the 'socket' object synchronously? 
    $http.get("something/that/returns/data") 
     .then(function (result) { 
      socket = createConnection(result.data); 
     }, function (err) { 
      // handle error 
     }); 

    var getSocket = function() { 
     if (!socket) { 
      // handle error 
     } else { 
      return socket; 
     } 
    } 
}]) 

myapp.config(function($stateProvider, $urlRouterProvider) { 
    $urlRouterProvider.otherwise("home"); 

    $stateProvider 
     .state('home', { 
      url: "/home", 
      templateUrl: "home.html", 
      resolve: { 
       socket: function(connectionService) { 
        return connectionService.getSocket(); 
       } 
      }, 
      controller: function(socket) { 
       socket.emit("some msg"); 
      } 
     }) 
     .state('nextState', { 
      url: "/next", 
      templateUrl: "next.html", 
      resolve: { 
       socket: function(connectionService) { 
        return connectionService.getSocket(); 
       } 
      }, 
      controller: function(socket) { 
       socket.emit("some other msg"); 
      } 
     }) 
}) 

アップデート2

が、これは正しい答えとして受け入れられてきたMuli Yulzariの答えのようにエレガントではありません。

私は自分の約束事を作り出し、それを解決するためにui-routerのためのものとして戻しました。私のデバッグとスタックのすべてのトレースに基づいて、状態間に1つの接続しか作成されず、接続が解決されるまでコントローラに入ることは延期されます。だから、これは実用的な解決策だと私は信じています。私は約束を解決する前に接続のonConnectイベントを処理するコードのバージョンを持っていますが、簡潔にするためにそれを省略しました。私の理解へ

var myapp = angular.module('me', ['ui.router']) 
.service('connectionService', ['$http', '$q', function($http, $q) { 
    var socket; 

    this.getSocket = function() { 
     if (!socket) { 
      var deferred = $q.defer(); 

      $http.get("something/that/returns/data") 
       .then(function (result) { 
        socket = createConnection(result.data); 
        deferred.resolve(socket); 
       }, function (err) { 
        // handle error 
        deferred.reject(socket); 
       }); 

      return deferred.promise; 
     } else { 
      return socket; 
     } 
    } 
}]) 

myapp.config(function($stateProvider, $urlRouterProvider) { 
    $urlRouterProvider.otherwise("home"); 

    $stateProvider 
     .state('home', { 
      url: "/home", 
      templateUrl: "home.html", 
      resolve: { 
       socket: function(connectionService) { 
        return connectionService.getSocket(); 
       } 
      }, 
      controller: function(socket) { 
       socket.emit("some msg"); 
      } 
     }) 
     .state('nextState', { 
      url: "/next", 
      templateUrl: "next.html", 
      resolve: { 
       socket: function(connectionService) { 
        return connectionService.getSocket(); 
       } 
      }, 
      controller: function(socket) { 
       socket.emit("some other msg"); 
      } 
     }) 
}) 
+0

アングルでは、サービスはシングルトンなので、実際にはあなたが望むものになります。しかし、サービスの構築方法にはいくつかの問題があります。具体的には、 '.this'は親サービスではなくコールバックを参照するため、あなたの意図通りに' .this'をコールバック内で使用することはできません。また、廃止予定の '.success'の代わりに' .then'に切り替えることも考慮する必要があります。 – Claies

+0

廃止予定の '.success'を削除し、'に切り替えました。それから約束する。 – BoJoe22

+1

あなたはまだpromiseの中で '.this'を使っています。これは動作しない主な部分です。 – Claies

答えて

0

、あなたはソケットインスタンスが無効である$http.get毎回からのデータに基づいてソケットを初期化しますが、アプリケーションのロード中に非同期的にそうしたいです。

.service('connectionService', ['$http', '$q', function($http, $q) { 
    //For caching the socket 
    var socket; 

    //Do the first get 
    tryGetData(); 

    //tryGetData executes $http.get and returns a promise that when fulfilled - 
    //returns the new socket instance. 
    function tryGetData(){ 
    return $http.get("something/that/returns/data") 
     .then(function (result) { 
      return socket = createConnection(result.data); 
     }, function (err) { 
      // handle error 
     }); 
    } 

    //Whenever getSocket gets called, it first checks if the socket is instantiated. if not - 
    //assumes the $http.get failed and tries again to instantiate the socket calling 
    //$http.get again in the process. 
    //this function returns a promise for controllers to rely on. 
    this.getSocket = function(){ 
    if(socket) return $q.resolve(socket); 
    return tryGetData(); 
    } 
}]); 

残りのコードは正常です。

+0

これは近いですが、tryGetData()はui-routerの解決が処理できる約束を返しません。私は、$ q遅延オブジェクトを作成し、その遅延オブジェクトの約束を返す場所で動作するソリューションを持っています。私はその解決策を投稿しますが、あなたの助けにあなたに信用を与えたいと思います。 – BoJoe22

+0

です。 https://docs.angularjs.org/api/ng/service/$http#get –

+0

はい、 '$ http'は約束を返します。しかしここで書かれているように、 'tryGetData()'は '.then()'がすでに呼び出されているので、その約束を返しません。適切な用語で説明する方法がわからないまた、約束の結果を返す前に '$ http.get'から返されるデータを処理する方法が必要でした。だから、私は '$ http'の約束を守り、もう一度やり直す必要がありました。少なくともそれが私の観察でした。私は完全に間違っているかもしれません... – BoJoe22

関連する問題