2017-05-26 19 views
3

私のサービスクラスでは、http取得要求をループしていて、rxjs forkJoinを使用して、すべての応答をコンポーネントに返す観測値に結合します。戻ってくる応答ごとに、jsonに2つのプロパティを追加する必要があります(readySystemはオブジェクトで、serviceTypeは文字列です)。これらのそれぞれの値は、ループの反復ごとに異なります。応答への角ループHTTP要求マップ値

andとmapの両方の値を保存/保持する方法/正しい応答に追加する方法はありますか?

私はこれを以下のように試みましたが、両方の値は最終的な観測値で返されるすべての応答で同じです。

getServices() { 

    for (var x = 0; x < this.service.items.length; x++){ 
     var num = Object.keys(this.service.items[x].links).length; 

     for (var key in this.service.items[x].links) { 
      var systemName = this.service.items[x].systemName; 
      var environment = this.service.items[x].environment; 
      var server = this.service.items[x].server; 
      var port = this.service.items[x].port; 
      var linkName = this.service.items[x].links[key]; 
      var serviceType = key; 
      this.observables.push(
      this.http.get('http://localhost:3000/myapi/get/service?server=' + server + '&service=' + linkName) 
      .map((res:Response) => { 
       var output = res.json() 
       for (var obj in output) { 
        if (output.hasOwnProperty(obj)){ 

         var readySystem = new System(systemName, 
         environment, 
         server, 
         port, 
         linkName); 

        output[obj].System = readySystem; 
        output[obj].serviceType = serviceType; 
        } 
       } 
       return output; 
     }) 
      ); 
     } 
     }; 
     return Observable.forkJoin(this.observables); 
}; 

更新は:以下の答えで提供示唆したコードの変更で、私は次のように出力を得る:

0: Array(33) 
1: System 
    systemName: "my system" 
    environment: "my environment" 
    etc. 
2: "myservice" 
3: Array(35) 
4: System 
    etc. 
5: "myotherservice" 

しかし、必要とされるものは、次のとおりです。

0: Array(33) 
0: Object 
    > System 
     systemName: "my system" 
     environment: "my environment" 
     etc. 
    serviceType: "myservice" 
1: Object 
    > System 
     systemName: "my system" 
     environment: "my environment" 
     etc. 
    serviceType: "myotherservice" 
etc. 
1: Array(35) 
0: Object 

答えて

0

ジャスト追加これらの値は、Observable.ofを使用してフォークします。

function getObsevrables(observables, readySystem, serviceType) { 
    return Rx.Observable.forkJoin([ 
    Rx.Observable.of(readySystem), 
    Rx.Observable.of(serviceType), 
    ...observables 
    ]); 
} 

getObsevrables([Rx.Observable.of(1), Rx.Observable.of(2)], 
      {ready: true}, 'type1') 
    .subscribe(x=>console.log(x)) 

UPDATE:

私はあなたのコードを更新しようとしました。

getServices() { 

for (var x = 0; x < this.service.items.length; x++) { 
    var num = Object.keys(this.service.items[x].links).length; 

    for (var key in this.service.items[x].links) { 
    var systemName = this.service.items[x].systemName; 
    var environment = this.service.items[x].environment; 
    var server = this.service.items[x].server; 
    var port = this.service.items[x].port; 
    var linkName = this.service.items[x].links[key]; 
    var serviceType = key; 

    var readySystem = new System(systemName, 
     environment, 
     server, 
     port, 
     linkName); 

    // getObservables([Observable.of(1), Observable.of(2)], readySystem, serviceType).subscribe(x => console.log(x)); 

    this.observables.push(
     Observable.combineLatest(
     this.http.get('http://localhost:3000/myapi/get/service?server=' + server + '&service=' + linkName) 
     .map((res: Response) => { 
      var output = res.json(); 
      return output; 
     }); 
     }, 
     Observable.of(serviceType), 
     Observable.of(readySystem) 
    ) 
    ); 
} 
} 
+0

ありがとうございます。私は関数が何をしているのか理解していますが、{ready:true}の目的は何か、いつ、どこから関数を呼び出すべきですか? – HendPro12

+0

をループで実行すると、http呼び出しを行うオブザーバブルの配列が作成され、各forkJoin-readySystemとserviceTypeに対して2つの変数が作成されることがわかります。したがってObservable.ofを使用して観測可能な配列にそれらを追加するだけで、同じ結果が得られます。 –

+0

私のforkJoinは、私の内側と外側のループの外側のreturn文で発生しています。観察可能な配列にプッシュされる前に、個々のオブザーバブルのそれぞれに内部ループ内の2つの変数を追加する必要があると思います。 – HendPro12

0

単純な古典的なJSクロージャの問題かもしれません。すべての非同期呼び出し(http.get sおよびObservable.forkJoin)が解決されると、すべての機能は、var S(XNUMキーSYSTEMNAME環境サーバーポートスコープ...等)は、最後の値に設定されています(forループ内)。最も簡単な解決策は、ES6ブロックスコープのletまたはconstの宣言を使用することです。

だから、のようなものにあなたのコードを変更しよう:

for (let x = 0; x < this.service.items.length; x++){ 
    let num = Object.keys(this.service.items[x].links).length; 

    for (let key in this.service.items[x].links) { 
    let systemName = this.service.items[x].systemName; 
    let environment = this.service.items[x].environment; 
    let server = this.service.items[x].server; 
    let port = this.service.items[x].port; 
    let linkName = this.service.items[x].links[key]; 
    let serviceType = key; 

    let url = `http://localhost:3000/myapi/get/service?server=${server}&service=${linkName}`; 
    this.observables.push(this.http.get(url) 
     .map((res:Response) => { 
     let output = res.json(); 
     for (let obj in output) { 
      if (output.hasOwnProperty(obj)) { 

      let readySystem = new System(systemName, 
       environment, 
       server, 
       port, 
       linkName 
      ); 

      output[obj].System = readySystem; 
      output[obj].serviceType = serviceType; 
      } 
     } 
     return output; 
     } 
    )); 
    }}; 
    return Observable.forkJoin(this.observables); 
}; 

と一般的には、角度の2/4でコーディングするとき​​を使用しない理由はありません。

また、(私はthis.service.itemsは、そのプロパティの配列であると仮定)Array.forEach()機能を使用して、あなたの最初のforループを書き換えることができます:

this.service.items.forEach(item => { 
    let num = Object.keys(item.links).length; 

    for (let key in item.links) { 
    let systemName = item.systemName; 
    let environment = item.environment; 
    let server = item.server; 
    let port = item.port; 
    let linkName = item.links[key]; 
    let serviceType = key; 

    let url = `http://localhost:3000/myapi/get/service?server=${server}&service=${linkName}`; 
    this.observables.push(this.http.get(url) 
     .map((res:Response) => { 
     let output = res.json(); 
     for (let obj in output) { 
      if (output.hasOwnProperty(obj)) { 

      let readySystem = new System(systemName, 
       environment, 
       server, 
       port, 
       linkName 
      ); 

      output[obj].System = readySystem; 
      output[obj].serviceType = serviceType; 
      } 
     } 
     return output; 
     } 
    )); 
    }}; 
    return Observable.forkJoin(this.observables); 
}); 
0

それは閉鎖問題です。ここ

for (var key in this.service.items[x].links) { 
    var systemName = this.service.items[x].systemName; 

あなたはブロックが実行される新しいsystemName変数ごとに作成していると思うことがあります。あなたの元のコードに基づいています。実際、変数は一度作成され、ブロックが実行されるたびに新しい値が割り当てられます。ここ

this.observables.push(
      this.http.get('http://localhost:3000/myapi/get/service?server=' + server + '&service=' + linkName) 
      .map(res => { 
       var output = res.json() 
       for (var obj in output) { 
       if (output.hasOwnProperty(obj)){ 
        var readySystem = new System(systemName, 

map内部のコールバックはすぐにsystemNameが適切な値を持っているループ内で実行されていません。違いは、あなたが非同期呼び出しhttp.getを作るための下に重要です。後で実行するためにメモリに格納されます(http.getが結果を返す)。コールバックの格納された本体には、systemNameの値が格納されず、変数への参照のみが渡されます。

ループが実行されるたびに、新しい値がsystemNameに割り当てられ、コールバックが保存されます。ループが終了するまでに、systemNameの値がループによって割り当てられた最後の値になります。

いつかhttp.getリクエストが完了し、保存されたコールバックが実行され、systemNameとなり、すべて同じ最終値を取得します。これはあなたが経験していることです。

最も簡単な修正は実際にブロック実行ごとに新しいsystemName変数を作成することです。これは、varの代わりにletを使用することによって実現できます。関連するすべての変数にletを使用するだけで問題が解決されます。

let systemName = this.service.items[x].systemName; 
let environment = this.service.items[x].environment; 
let server = this.service.items[x].server; 
let port = this.service.items[x].port; 
let linkName = this.service.items[x].links[key]; 
let serviceType = key; 
関連する問題