2017-05-26 52 views
3

在我的服务类中,我正在循环一个http get请求,并使用rxjs forkJoin将所有响应组合到一个observable中,并将其返回给我的组件。对于每个返回的响应,我需要向json添加两个属性(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创建了两个变量。因此,您只需使用Observable.of将它们添加到可观察数组中,并执行与现在一样的返回。 –

+0

我的forkJoin发生在我的内部和外部循环外的return语句中。我相信我需要将内部循环中的两个变量添加到每个单独的observables中,然后将它们推入到我的observable数组中。 – HendPro12

0

这可能是一个简单的经典的JS关闭问题。当所有异步调用(http.get S和Observable.forkJoin)都解决了,所有的功能范围的var S(XNUM关键SYSTEMNAME环境服务器端口,...等等)在for循环内设置为它们的最后一个值。最简单的解决方案是使用ES6块范围letconst声明。

因此,尝试更改您的代码是这样的:

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编码时使用​​。

你也可以使用Array.forEach()功能(我认为this.service.items是因为它的长度财产的数组)重写你的第一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变量。这可以通过使用let而不是var来实现。所以只需使用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;