Angular Local HTTP request cost for responses

In my service class, I will loop the http get request and use rxjs forkJoin to combine all responses into observables, which I return to my component. For each response returned, I need to add two properties to the json (readySystem, which is an object and serviceType, which is a string). The meaning of each of them is different for each iteration of the loop.

How do I store / store / store the values ​​for both and and match / add them to the correct answer?

With the way I tried to do it below, the values ​​for both are the same in every response returned in the final observable.

  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);
};

      

Update . With the suggested code changes given in the answer below, I get an output like:

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

      

However, the following is required:

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

      

+3


source to share


3 answers


Just add these values ​​to fork using 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:



I tried to update your code.

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


source


This could be a simple classic JS closure problem. When all the asynchronous calls ( http.get

and Observable.forkJoin

) are allowed, all functions with domain var

(x, num, key, systemName , environment, server, port, ... , etc.) within loops for

fixed to their last value. The simplest solution would be to use ES6 declarations with blocks let

or const

.

So try changing your code to something like:

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);
};

      



and there is no reason at all not to use the new ES6 features when coding with Angular 2/4.

You can also rewrite your first loop for

using a function Array.forEach()

(I assume it this.service.items

is an array because of its length property):

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


source


This is a closure problem. Based on your source code:

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

      

here you might think that every time the block is executed you are creating a new variable systemName

. Indeed, the variable is created once and assigned a new value every time the block is executed. The difference is important because below you are making an asynchronous call http.get

:

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,

      

here the callback inside is map

not executed directly in the loop when it systemName

has the correct value. It is simply stored in memory for later execution (when it http.get

returns a result). The stored callback body does not carry a value systemName

, only a variable reference.

Now, every time the loop is executed, it assigns a new value systemName

and saves the callback. At the end of the cycle, the value systemName

is the last value specified by the cycle.

After a while, the requests http.get

start to complete, the stored callbacks are executed, they read systemName

, and they all get the same last value. This is what you are experiencing.

The simplest fix is ​​actually creating a new variable systemName

for each execution of the block. This can be achieved by using let

instead var

. So just using it let

for all relevant variables will fix the problem:

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;

      

0


source







All Articles