233

私は最近、ここSOで直面している問題の詳細な説明を投稿しました。実際の$httpリクエストを送信できなかったため、タイムアウトを使用して非同期動作をシミュレートしました。@Gloopyの助けを借りて、モデルからビューへのデータバインディングが正しく機能しています

$http代わりに(ローカルでテスト)を使用すると$timeout、非同期リクエストが成功dataし、サービスでjsonレスポンスで満たされていることがわかりました。しかし、私の見解は更新されていません。

ここでPlunkrを更新しました

4

12 に答える 12

418

これがあなたが望むことをするプランクです:http://plnkr.co/edit/TTlbSv ?p = Preview

アイデアは、promiseとその「then」関数を直接操作して、非同期で返された応答を操作およびアクセスすることです。

app.factory('myService', function($http) {
  var myService = {
    async: function() {
      // $http returns a promise, which has a then function, which also returns a promise
      var promise = $http.get('test.json').then(function (response) {
        // The then function here is an opportunity to modify the response
        console.log(response);
        // The return value gets picked up by the then in the controller.
        return response.data;
      });
      // Return the promise to the controller
      return promise;
    }
  };
  return myService;
});

app.controller('MainCtrl', function( myService,$scope) {
  // Call the async method and then do stuff with what is returned inside our own then function
  myService.async().then(function(d) {
    $scope.data = d;
  });
});

これは、リクエストをキャッシュする少し複雑なバージョンであるため、最初にのみ作成します(http://plnkr.co/edit/2yH1F4IMZlMS8QsV9rHv?p=preview):

app.factory('myService', function($http) {
  var promise;
  var myService = {
    async: function() {
      if ( !promise ) {
        // $http returns a promise, which has a then function, which also returns a promise
        promise = $http.get('test.json').then(function (response) {
          // The then function here is an opportunity to modify the response
          console.log(response);
          // The return value gets picked up by the then in the controller.
          return response.data;
        });
      }
      // Return the promise to the controller
      return promise;
    }
  };
  return myService;
});

app.controller('MainCtrl', function( myService,$scope) {
  $scope.clearData = function() {
    $scope.data = {};
  };
  $scope.getData = function() {
    // Call the async method and then do stuff with what is returned inside our own then function
    myService.async().then(function(d) {
      $scope.data = d;
    });
  };
});
于 2012-09-20T13:19:10.247 に答える
82

簡単にしましょう。それは同じくらい簡単です

  1. サービスに戻るpromise(サービスで使用する必要はありませんthen
  2. thenコントローラで使用する

デモ。http://plnkr.co/edit/cbdG5p?p=preview

var app = angular.module('plunker', []);

app.factory('myService', function($http) {
  return {
    async: function() {
      return $http.get('test.json');  //1. this returns promise
    }
  };
});

app.controller('MainCtrl', function( myService,$scope) {
  myService.async().then(function(d) { //2. so you can use .then()
    $scope.data = d;
  });
});
于 2013-12-20T21:34:25.223 に答える
58

非同期であるため、は$scopeajax呼び出しが完了する前にデータを取得しています。

$qサービスで使用して作成promiseし、コントローラーに返すことができます。コントローラーは、then()に対する呼び出し内で結果を取得しpromiseます。

あなたのサービスでは、

app.factory('myService', function($http, $q) {
  var deffered = $q.defer();
  var data = [];  
  var myService = {};

  myService.async = function() {
    $http.get('test.json')
    .success(function (d) {
      data = d;
      console.log(d);
      deffered.resolve();
    });
    return deffered.promise;
  };
  myService.data = function() { return data; };

  return myService;
});

次に、コントローラーで:

app.controller('MainCtrl', function( myService,$scope) {
  myService.async().then(function() {
    $scope.data = myService.data();
  });
});
于 2012-09-20T05:35:40.227 に答える
23

tosh shimayamaには解決策がありますが、$ httpがpromiseを返し、promiseが値を返すことができるという事実を使用すると、多くのことを単純化できます。

app.factory('myService', function($http, $q) {
  myService.async = function() {
    return $http.get('test.json')
    .then(function (response) {
      var data = reponse.data;
      console.log(data);
      return data;
    });
  };

  return myService;
});

app.controller('MainCtrl', function( myService,$scope) {
  $scope.asyncData = myService.async();
  $scope.$watch('asyncData', function(asyncData) {
    if(angular.isDefined(asyncData)) {
      // Do something with the returned data, angular handle promises fine, you don't have to reassign the value to the scope if you just want to use it with angular directives
    }
  });

});

Coffeescriptでのちょっとしたデモンストレーション:http://plunker.no.de/edit/ksnErx?live = Preview

あなたのプランカーは私の方法で更新されました: http://plnkr.co/edit/mwSZGK?p = Preview

于 2012-09-20T08:43:54.233 に答える
7

私が思うはるかに良い方法は次のようなものになるでしょう:

サービス:

app.service('FruitsManager',function($q){

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

        ...

        // somewhere here use: deferred.resolve(awesomeFruits);

        ...

        return deferred.promise;
    }

    return{
        getAllFruits:getAllFruits
    }

});

そして、コントローラーでは、次のように簡単に使用できます。

$scope.fruits = FruitsManager.getAllFruits();

Angularは自動的に解決さawesomeFruitsれたものをに入れ$scope.fruitsます。

于 2013-11-03T15:11:51.553 に答える
6

同じ問題が発生しましたが、インターネットでネットサーフィンをしているときに、$ httpがデフォルトで約束を返すことを理解しました。その後、「データ」を返した後、「then」で使用できます。コードを見てください:

 app.service('myService', function($http) {
       this.getData = function(){
         var myResponseData = $http.get('test.json').then(function (response) {
            console.log(response);.
            return response.data;
          });
         return myResponseData;

       }
});    
 app.controller('MainCtrl', function( myService, $scope) {
      // Call the getData and set the response "data" in your scope.  
      myService.getData.then(function(myReponseData) {
        $scope.data = myReponseData;
      });
 });
于 2017-01-19T23:20:54.913 に答える
4

UIを配列にバインドするときは、長さを0に設定し、データを配列にプッシュすることで、同じ配列を直接更新する必要があります。

これの代わりに(dataUIが認識しない別の配列参照を設定します):

 myService.async = function() {
    $http.get('test.json')
    .success(function (d) {
      data = d;
    });
  };

これを試して:

 myService.async = function() {
    $http.get('test.json')
    .success(function (d) {
      data.length = 0;
      for(var i = 0; i < d.length; i++){
        data.push(d[i]);
      }
    });
  };

これは、新しい配列を設定することと、既存の配列を空にして追加することの違いを示すフィドルです。私はあなたのplnkrを動作させることができませんでしたが、うまくいけばこれはあなたのために動作します!

于 2012-09-20T04:47:55.007 に答える
4

これに関連して、私は同様の問題を経験しましたが、Angularによって作成されたgetまたはpostではなく、サードパーティによって作成された拡張機能(私の場合はChrome拡張機能)を使用しました。
私が直面した問題は、Chrome拡張機能が戻らないthen()ため、上記の解決策ではそれを行うことができなかったが、結果は依然として非同期であるということです。
だから私の解決策は、サービスを作成してコールバックに進むことです

app.service('cookieInfoService', function() {
    this.getInfo = function(callback) {
        var model = {};
        chrome.cookies.get({url:serverUrl, name:'userId'}, function (response) {
            model.response= response;
            callback(model);
        });
    };
});

それから私のコントローラーで

app.controller("MyCtrl", function ($scope, cookieInfoService) {
    cookieInfoService.getInfo(function (info) {
        console.log(info);
    });
});

これが他の人が同じ問題を抱えるのを助けることができることを願っています。

于 2013-06-23T11:52:46.583 に答える
4

http://markdalgleish.com/2013/06/using-promises-in-angularjs-views/ [AngularJSを使用すると、解決済みのファイルを手動で渡すのではなく、スコープに直接promiseを配置することで、コントローラーロジックを合理化できます。成功コールバックの値。]

とてもシンプルで便利です:)

var app = angular.module('myApp', []);
            app.factory('Data', function($http,$q) {
                return {
                    getData : function(){
                        var deferred = $q.defer();
                        var promise = $http.get('./largeLoad').success(function (response) {
                            deferred.resolve(response);
                        });
                        // Return the promise to the controller
                        return deferred.promise; 
                    }
                }
            });
            app.controller('FetchCtrl',function($scope,Data){
                $scope.items = Data.getData();
            });

この助けを願っています

于 2013-09-13T16:22:20.140 に答える
2

「約束」のやり方のために、$ httpを使用するサービスの利用者は、応答を解凍する方法を「知っている」必要があるという事実は本当に好きではありません。

$scope.items = Data.getData();以前の方法と同様に、何かを呼び出してデータを取得したいだけですが、現在は非推奨になっています。

しばらく試してみましたが、完璧な解決策は思いつきませんでしたが、これが私のベストショットです(Plunker)。それは誰かに役立つかもしれません。

app.factory('myService', function($http) {
  var _data;  // cache data rather than promise
  var myService = {};

  myService.getData = function(obj) { 
    if(!_data) {
      $http.get('test.json').then(function(result){
        _data = result.data;
        console.log(_data);  // prove that it executes once
        angular.extend(obj, _data);
      }); 
    } else {  
      angular.extend(obj, _data);
    }
  };

  return myService;
}); 

次にコントローラー:

app.controller('MainCtrl', function( myService,$scope) {
  $scope.clearData = function() {
    $scope.data = Object.create(null);
  };
  $scope.getData = function() {
    $scope.clearData();  // also important: need to prepare input to getData as an object
    myService.getData($scope.data); // **important bit** pass in object you want to augment
  };
});

私がすでに見つけられる欠陥は

  • データを追加するオブジェクトを渡す必要がありますが、これはAngularの直感的または一般的なパターンではありません
  • getDataオブジェクトの形式でのみobjパラメータを受け入れることができます(ただし、配列を受け入れることもできます)。これは多くのアプリケーションにとって問題にはなりませんが、それはひどい制限です。
  • 入力オブジェクト$scope.data= {}オブジェクト(基本的に$scope.clearData()は上記で行うこと)にする= []ため、または配列用に準備する必要があります。そうしないと、機能しません(どのデータが来るかについてはすでに想定している必要があります)。私はこの準備ステップをINgetDataで実行しようとしましたが、うまくいきませんでした。

それでも、コントローラーの「promise unwrap」ボイラープレートを削除するパターンを提供し、$ httpから取得した特定のデータを、DRYのままで複数の場所で使用する場合に役立つことがあります。

于 2014-09-24T17:43:16.213 に答える
1

応答をサービスにキャッシュすることに関する限り、これまでに見たものよりも簡単に見える別のバージョンがあります。

App.factory('dataStorage', function($http) {
     var dataStorage;//storage for cache

     return (function() {
         // if dataStorage exists returned cached version
        return dataStorage = dataStorage || $http({
      url: 'your.json',
      method: 'GET',
      cache: true
    }).then(function (response) {

              console.log('if storage don\'t exist : ' + response);

              return response;
            });

    })();

});

このサービスは、キャッシュされたデータまたは$http.get;のいずれかを返します。

 dataStorage.then(function(data) {
     $scope.data = data;
 },function(e){
    console.log('err: ' + e);
 });
于 2015-09-28T17:23:10.307 に答える
0

以下のコードをお試しください

コントローラ(PageCtrl)とサービス(dataService)を分割できます

'use strict';
(function () {
    angular.module('myApp')
        .controller('pageContl', ['$scope', 'dataService', PageContl])
        .service('dataService', ['$q', '$http', DataService]);
    function DataService($q, $http){
        this.$q = $q;
        this.$http = $http;
        //... blob blob 
    }
    DataService.prototype = {
        getSearchData: function () {
            var deferred = this.$q.defer(); //initiating promise
            this.$http({
                method: 'POST',//GET
                url: 'test.json',
                headers: { 'Content-Type': 'application/json' }
            }).then(function(result) {
                deferred.resolve(result.data);
            },function (error) {
                deferred.reject(error);
            });
            return deferred.promise;
        },
        getABCDATA: function () {

        }
    };
    function PageContl($scope, dataService) {
        this.$scope = $scope;
        this.dataService = dataService; //injecting service Dependency in ctrl
        this.pageData = {}; //or [];
    }
    PageContl.prototype = {
         searchData: function () {
             var self = this; //we can't access 'this' of parent fn from callback or inner function, that's why assigning in temp variable
             this.dataService.getSearchData().then(function (data) {
                 self.searchData = data;
             });
         }
    }
}());

于 2016-11-23T01:37:41.550 に答える