5

There is a function that first gets all zones in an environment and then when he found these zones for each zone it will do an api call for the borderpoints. All fetches get executed but the problem is that in the then for the first fetch if I try to write out the length of the zones or try to do a .foreach I get 0.

I know this is because it runs async and it is not yet loaded on the moment I do the console.log but I tought it should be. That's why we use the .then isn't it? to wait until the data has been loaded.

To be clear: I'm looking for a way to make zones.length give back the real length of the array of objects and be evaluated immediately instead of 0. I can't find out how:

Here is the code.

getZones(){
      var that = this;
  var zones = new Array();
  fetch('api/environment/zone/1').then(function(response){
    response.json().then(function(data){
      data.forEach(function(element){
        zones[element.zoneID] = element;
        zones[element.zoneID].points = [];
        fetch('api/zone/point/'+element.zoneID).then(function(response){
          response.json().then(function(data){
            data.forEach(function(element){
              zones[element.zoneID].points.push(element);  
            });
          }); //closing of data inner fetch.
          });
        });
      });
    }).then(function(response){
      console.log(zones); //this gives all zones
      console.log(zones.length); //this one gives 0
//the for each is never executed because it's still 0.
      zones.forEach(function(element){  
        console.log(element);
      });
    });
  }

Already a big thanks for the fast Reaction and help.

2
  • I think you are wrongly using the async methods. But still answering to the question, your zones.length is 0 because it is an object i believe. Why don't you try Object.keys(zones).length instead of zones.length and see if you get an output ? Commented Apr 23, 2017 at 10:45
  • @Panther I can't because the zones are not yet loaded when that log is excecuted. I will get a "cannot read property of undefined" that's the complete problem. I first tought the .then would make sure that everything would be loaded but I really don't know what I'm doing wrong. Commented Apr 23, 2017 at 10:52

2 Answers 2

2

In the end I fixed it in a more beautiful way:

getZones2(){
      var that = this;
      var zones = [];
  fetch('api/environment/zone/1')
    .then(res => res.json())
    .then((json) => {
      Promise.all(
        json.map(
          element => fetch('api/zone/point/' + element.zoneID)
            .then(res => res.json())
        )
      ).then(datas => {
        json.forEach((element, i) => {
          zones[element.zoneID] = element
          zones[element.zoneID].points = datas[i]

        })
        console.log(zones);
        zones.forEach(function(response){
            that.makeZone(response.name,response.zoneID,response.points);
        })
      })
    });
}
Sign up to request clarification or add additional context in comments.

Comments

0

The calls to fetch returns an Promise and that is async. So your second .then executes before even the code inside the first then completes because, your first then contains another fetch function being called which is async. You can have a logic like below to wait until you get all points data and the proceed with your logic.

    getZones(){
          var that = this;
          // var zones = new Array();

          // this function gets called finally.
          // Do what you want to do with zones and points here.
          var gotAllZones = function(zones) {

              console.log(zones); //this gives all zones
              console.log(Object.keys(zones).length); //this one gives 0

              Object.keys(zones).forEach(function(index){  
                console.log(zones[index]);
              });
          }

          fetch('api/environment/zone/1').then(function(response){
            response.json().then(function(data){
              //decleare zones to be a object. Based on your code `zones` is not an array
              var zones = {};
              var pointsDone = 0; // declare how many points api has been completed. Initially its `0`
              data.forEach(function(element){
                zones[element.zoneID] = element;
                zones[element.zoneID].points = [];
                fetch('api/zone/point/'+element.zoneID).then(function(response){
                  response.json().then(function(innerData){
                    innerData.forEach(function(element){
                      zones[element.zoneID].points.push(element);  
                    });
                    pointsDone++; //each time we are done with one. we increment the value.

                    // we check if we are done collecting all points data
                    // if so we can call the final function. 
                    if(pointsDone === data.length) {
                      gotAllZones(zones);
                    }
                  }); //closing of data inner fetch.
                  });
                });
              });
            })
      }

1 Comment

Jup it works, thank you very very VERY much. It doesn't look very beautiful but... ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.