combi35
combi35

Reputation: 487

no scope in loop $http get?

I am using 2 API Points. First one is to get all the exchanges and the second to print the BTC price on every exchange from the first point. I then want to combine both calls to 1 Object

var app = angular.module("App", []);   
app.controller("Ctrl", function ($scope, $http) {
    var rand = [];
    $http({
        method: "GET",
        url: "https://min-api.cryptocompare.com/data/all/exchanges" 
    }).then(function success(response) {
        var datas = response.data;
        for (var prop in datas) {

            $http.get("https://min-api.cryptocompare.com/data/pricemulti?fsyms=BTC&tsyms=USD&e=" + prop)
            .then(function success(responsePrice) {
            rand.push({'exchange' : prop, 'price' : responsePrice.data});
            })
        }

    });
    console.log(rand);
});

API points are working fine if i dont put them together. Is it bad to have a loop in my http get? Seems that i have no scope after the success function, so prop is always displayed as the last exchange. Would be very thankful for help. Thanks

Upvotes: 1

Views: 54

Answers (3)

Rahul Sharma
Rahul Sharma

Reputation: 10071

try this

var app = angular.module("App", []);
app.controller("Ctrl", function ($scope, $http) {
    var rand = [];
    $http({
        method: "GET",
        url: "https://min-api.cryptocompare.com/data/all/exchanges"
    }).then(function success(response) {
        var datas = response.data;
        var keys = Object.keys(datas);
        var promises = keys.map(prop =>
            $http.get("https://min-api.cryptocompare.com/data/pricemulti?fsyms=BTC&tsyms=USD&e=" + prop));

        Promise.all(promises).then((response) => {
            rand = response.map((responsePrice, index) => {
                return {
                    'exchange': keys[index],
                    'price': responsePrice.data
                };
            });
            console.log(rand);
        }).catch((err) => {
            console.log(err);
        });

    });
});

Upvotes: 0

Arun Redhu
Arun Redhu

Reputation: 1579

Your scope for prop will always be lost because of async task in the loop. To retain the scope of prop you have to use let instead of var because var have function scope and and let have block scope. So your modified code will be as

var app = angular.module("App", []);   
app.controller("Ctrl", function ($scope, $http) {
    var rand = [];
    $http({
        method: "GET",
        url: "https://min-api.cryptocompare.com/data/all/exchanges" 
    }).then(function success(response) {
        var datas = response.data;
        for (let prop in datas) {

            $http.get("https://min-api.cryptocompare.com/data/pricemulti?fsyms=BTC&tsyms=USD&e=" + prop)
            .then(function success(responsePrice) {
            rand.push({'exchange' : prop, 'price' : responsePrice.data});
            })
        }

    });
    console.log(rand);
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

Upvotes: 1

I. Ahmed
I. Ahmed

Reputation: 2534

Yes, your following loop has problem:

      for (var prop in datas) {

            $http.get("https://min-api.cryptocompare.com/data/pricemulti?fsyms=BTC&tsyms=USD&e=" + prop)
            .then(function success(responsePrice) {
            rand.push({'exchange' : prop, 'price' : responsePrice.data});
            })
        }

The line for (var prop in datas) { executes all of its iteration and points to the last element before finish the $http.get request as its asynchronous request.

So, to achieve this, some mechanism need to ensure the valid data present at the time of $http.get call.

Now to do this, an array has been created by using the following code as the return value is a map and its difficult to use in next recursive function:

datas = response.data;
console.log(datas);
for (var prop in datas) {
   propArray.push(prop);
}

The following recursive function ensures the value of your used prop item updated after each $http.get has been completed:

var dataAcquireLoop = function () {
    dataIndex++;
    if(dataIndex >= propArray.length) {
        console.log(rand);
        return;
    }
    console.log(propArray[dataIndex]);
    $http.get("https://min-api.cryptocompare.com/data/pricemulti?fsyms=BTC&tsyms=USD&e=" + propArray[dataIndex])
    .then(
        function success(responsePrice) {
            rand.push({'exchange' : propArray[dataIndex], 'price' : responsePrice.data});
            dataAcquireLoop();
        },
        function(error) {
            dataAcquireLoop();
        }
    );

}

The final updated code given below:

app.controller("Ctrl", function ($scope, $http) {
var rand = [];
var datas = [];
var dataIndex = -1;
var propArray = [];
var dataAcquireLoop = function () {
    dataIndex++;
    if(dataIndex >= propArray.length) {
        console.log(rand);
        return;
    }
    console.log(propArray[dataIndex]);
    $http.get("https://min-api.cryptocompare.com/data/pricemulti?fsyms=BTC&tsyms=USD&e=" + propArray[dataIndex])
    .then(
        function success(responsePrice) {
            rand.push({'exchange' : propArray[dataIndex], 'price' : responsePrice.data});
            dataAcquireLoop();
        },
        function(error) {
            dataAcquireLoop();
        }
    );

}

$http({
    method: "GET",
    url: "https://min-api.cryptocompare.com/data/all/exchanges" 
}).then(function success(response) {
    datas = response.data;
    console.log(datas);
    for (var prop in datas) {
       propArray.push(prop);
    }
    dataAcquireLoop();
});
});

Upvotes: 0

Related Questions