回答:
ここにあなたが望むことをするPlunkがあります: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;
});
};
});
myService.async()
さまざまなコントローラーから複数回呼び出す場合$http.get()
は、最初の要求に対してのみを実行するようにサービスを編成し、その後のすべての要求がへの最初の呼び出しで設定されるローカルオブジェクト配列を返すだけmyService.async()
です。つまり、実際に1つだけ作成する必要がある場合に、JSONサービスへの複数の不要な要求を回避したいのです。
$scope.data = myService.async()
コントローラで直接使用することもできると思います。
簡単にしましょう。それはと同じくらい簡単です
promise
サービスに戻る(then
サービスで使用する必要はありません)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;
});
});
app.factory
、そしてあなたのコードではそれapp.service
です。app.factory
この場合を想定しています。
非同期であるため、は$scope
ajax呼び出しが完了する前にデータを取得しています。
$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();
});
});
this.async = function() {
とはthis.getData = function() {return data}
?私は、あなたは私が何を意味するかを取得願っています
deffered = $q.defer()
2つの以上の時)私はmyService.asyncを(呼び出したい場合myService.async内
$q.defer
ので、プロミスを作成する必要はありません$http
。が$http
エラーを返した場合、返されたpromiseはハングします。さらに、.success
および.error
メソッドは廃止され、AngularJS 1.6から削除されました。
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
私が考えるはるかに良い方法は次のようなものです:
サービス:
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
ます。
私は同じ問題を抱えていましたが、インターネットでサーフィンをしているときに、$ httpがデフォルトでプロミスに戻ることを理解していたので、「データ」を返した後に「それから」でそれを使用できました。コードを見てください:
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;
});
});
UIを配列にバインドするときは、長さを0に設定してデータを配列にプッシュすることにより、同じ配列を直接更新する必要があります。
これの代わりに(data
UIが認識しない別の配列参照を設定します):
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を動作させることができませんでしたが、うまくいけばこれはあなたのためにうまくいきます!
angular.copy(d, data)
も動作します。宛先がcopy()メソッドに提供されると、宛先の要素が最初に削除され、次にソースから新しい要素がコピーされます。
これに関連して、私は同様の問題を経験しましたが、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);
});
});
これが他の人が同じ問題を解決するのに役立つことを願っています。
http://markdalgleish.com/2013/06/using-promises-in-angularjs-views/を読みました [AngularJSを使用すると、手動で解決策を渡すのではなく、スコープに直接プロミスを配置することでコントローラーロジックを合理化できます成功コールバックの値。]
とても簡単で便利です:)
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();
});
この助けを願っています
defrred.promise
関数ではありません。
$scope.items = Data.getData();
はAnglularでは推奨されていません
「約束」の方法のため、$ 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
};
});
私がすでに見つけることができる欠陥は
getData
obj
オブジェクトの形式でのみパラメーターを受け入れることができます(ただし、配列を受け入れることもできます)。これは、多くのアプリケーションでは問題にはなりませんが、制限があります。$scope.data
し= {}
て、それをオブジェクト(基本的に$scope.clearData()
上記で何が行われるか)にするか= []
、配列にする必要があります。そうしないと機能しません(データが何であるかについてはすでに想定している必要があります)。私はこの準備ステップをINにしようとしましたgetData
が、うまくいきませんでした。それにもかかわらず、これはコントローラーの「promise unwrap」ボイラープレートを削除するパターンを提供し、DRYを維持しながら$ httpから取得した特定のデータを複数の場所で使用したい場合に役立つことがあります。
サービスでの応答のキャッシュに関する限り、これまでに見たものよりも簡単に見える別のバージョンを次に示します。
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);
});
以下のコードをお試しください
コントローラ(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;
});
}
}
}());
then
か?