2016-10-12 4 views
1

これは1万回質問されるかもしれませんが、この問題に対する適切な解決策はまだ見つかりません。

私はちょうど$httpをAPI(またはJSONファイル)から非同期的にフェッチするために、サービスからデータを取得するコントローラの古典的な例を持っています。コントローラ内のデータはサービス内のオブジェクトへの参照であるため、サービスが完了した時点でデータが変更されることを期待していたため、ビューが更新されることを期待していました。下のスニペットで見ることができるように、ビューは初期値を保持します。

このように、私の二つの質問:

  1. これは良好なパターンますか?コントローラが複数存在し、特定の時点でデータを再フェッチする必要があるとします(コントローラで更新される)。
  2. ビューが更新されないのはなぜですか?

$ scope(可能な場合)や$ rootSscope、$ watchも使用しないことに注意してください。

var app = angular.module('myApp', []) 
 
.service('Service', ['$http', service]) 
 
.controller('Controller', ['Service', controller]); 
 

 

 
function controller(Service){ 
 
    var c = this; 
 
    c.items = [ 
 
     {'title': 'Default title1'}, 
 
     {'title': 'Default title2'} 
 
    ]; 
 
    c.items = Service.data; 
 
} 
 

 
function service($http, $scope){ 
 
    var data = [ 
 
     {'title': 'olddatatitle'} 
 
    ]; 
 
    $http({ 
 
     method: 'GET', 
 
     url: 'https://jsonplaceholder.typicode.com/posts?userId=1', 
 
     cache: true 
 
    }).then(function(response){ 
 
     data = response.data; 
 
    }); 
 
    return { 
 
     data: data 
 
    } 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 
<div ng-app="myApp" > 
 
    <ul ng-controller="Controller as c"> 
 
    <li ng-repeat="item in c.items"> 
 
     {{item.title}} 
 
    </li> 
 
    </ul> 
 
</div>

+0

$のHTTP呼び出しは、あなたのコード内で非同期に実行されます。 returnステートメントは、$ httpを呼び出した直後に発生し、 'then'は後で発生します。データを更新するためのコールバックを提供するか、または約束を返し、呼び出し元に自分のコールバックを指定させる必要があります。 – Igor

+0

[非同期呼び出しから応答を返すにはどうすればよいですか?](http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – Igor

答えて

2

あなたの問題は非同期のものです...あなたのサービス内の$httpからデータを取得したいのではなく、コントローラが準備ができたら準備ができていると思います。

function service($http, $scope){ 
    //var data = [ 
    // {'title': 'olddatatitle'} 
    //]; 

    return { 
     getData: function() { 
     return $http({ // calls to $http return a promise object 
      method: 'GET', 
      url: 'https://jsonplaceholder.typicode.com/posts?userId=1', 
      cache: true 
     }); 
    } 
} 

データが消費する準備ができたとき、あなたのコントローラが正確に知っているその方法は:

function controller(Service){ 
    var c = this; 
    //c.items = [ 
    // {'title': 'Default title1'}, 
    // {'title': 'Default title2'} 
    //]; 
    Service.getData().then(function(response) { // the promise object allows you to assign data only when it's ready 
     c.items = response.data 
    }); 
} 
+1

補足として、サービスは実際にはファクトリとして定義されています。サービスは 'return'ステートメントを使用しませんが、工場は行いますが、これは明確化のために一般的な考えを与えるべきです。 –

+0

私は誤って、 'データ'が(非同期呼び出しの後に)更新されると仮定していたため、そのオブジェクトへの参照です。オブジェクトがどのように渡されるかを理解する必要があります。 – stilllife

+1

@stilllife - オブジェクト 'data'を渡して新しい値でそのオブジェクトを更新すると動作します。あるいは、後で更新するオブジェクトを返すこともできます。しかし、 'then'コードはオブジェクトを更新するのではなく、ポインタを新しいオブジェクトに割り当てます。その時点では、2つのオブジェクトがメモリにあります(ポインタは移動しませんが、短いままです)。代入演算子を使うたびに、そのポインタを他のものを指すように再割り当てします。 – Igor

0
c.items = Service.data; 

あなたのAPIはレスポンスを返すまでに、JSは、すでに次の文に上を移動しているように、上記の行は、API呼び出しの応答がありません... callbackを提供する必要があります。

0

あなたは理解していない代わりにデータの約束を返し、データを返すようにしようとしないでください何がpromiseです。実際には、データではなくサービスから約束を返す必要があります。サービス定義の時点では、データはありません。あなたがサービスのためにあなたの電話を完了した後にそこにいることが起こります。だから、約束で動作する部分がないサービス定義では、サービスを利用するコードを呼び出すにする必要があります。

var app = angular.module('myApp', []) 
 
.service('Service', ['$http', service]) 
 
.controller('Controller', ['Service', controller]); 
 

 

 
function controller(Service){ 
 
    var c = this; 
 
    c.items = [ 
 
     {'title': 'Default title1'}, 
 
     {'title': 'Default title2'} 
 
    ]; 
 
    Service.get().then(function(payload) { 
 
    console.log(payload); 
 
     c.items = payload.data; 
 
    }); 
 
} 
 

 
function service($http, $scope){ 
 
    var data = [ 
 
     {'title': 'olddatatitle'} 
 
    ]; 
 
    var get = function() { 
 
    return $http({ 
 
     method: 'GET', 
 
     url: 'https://jsonplaceholder.typicode.com/posts?userId=1', 
 
     cache: true 
 
    })}; 
 
    return { 
 
     get: get 
 
    } 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 
<div ng-app="myApp" > 
 
    <ul ng-controller="Controller as c"> 
 
    <li ng-repeat="item in c.items"> 
 
     {{item.title}} 
 
    </li> 
 
    </ul> 
 
</div>

+0

ありがとう、私は約束を使用します。しかし、あなたのスニペットはまだデフォルトのデータを表示しています。なぜなのかご存知ですか ? – stilllife

+0

@stilllife私の悪い、私はちょうど必要以上に少しを省略しました。 –

関連する問題