Mayukh Bhattacharyya Mayukh Bhattacharyya - 3 months ago 14
AngularJS Question

Javascript array element undefined

I am trying out some angularjs stuff. So I have a few arrays. One of them is artists. this is it's basic structure from

console.log(artists);


artists

problem is that I can't access the elements of the array individually. I read up a lot of things regarding associative arrays and may questions on SO but none really helped. So either it is a very silly mistake I am making or it is some thing else.

Here are few results that I got with every array I have.

console.log(artists[0]); //returns undefined
console.log(artists['0']); //returns undefined
console.log(artists.length); // returns 0 in spite of the fact it showed 20 previously
console.log(Array.isArray(artists)); //returns true


And yes I created the array like this in a service, ChartService

var artists = [];
var artistids = [];
var tracks = [];

$http.get('https://api.spotify.com/v1/search/?q=genre:pop&type=artist').success(function (data) {
var items = data.artists.items;
items.forEach(function(item){
artists.push(item.name);
artistids.push(item.id);
var query = trackApi+item.id+'/top-tracks?country=SE'

$http.get(query).success(function (response) {
tracks.push({'preview': response.tracks[0].preview_url});

});
});


});

return {
Artists : artists,
Tracks : tracks
}


And my controller

console.log(ChartService.Artists); //runs fine
console.log(ChartService.Tracks); //runs fine

$scope.tracks = ChartService.Tracks;

console.log($scope.tracks); //runs fine
console.log($scope.tracks[0]); //returns undefined
console.log($scope.tracks['0']); //returns undefined
console.log($scope.tracks.length); // returns 0 in spite of the fact it showed 20 previously
console.log(Array.isArray($scope.tracks)); //returns true

Answer

The issue is that you check the content of artists before the issued http get requests have triggered their responses.

One way to resolve that is to put your code in the success callback, like this:

$http.get('https://api.spotify.com/v1/search/?q=genre:pop&type=artist').success(function (data) {
    var items = data.artists.items;
    items.forEach(function(item){
        artists.push(item.name);
        artistids.push(item.id);
        var query = trackApi+item.id+'/top-tracks?country=SE'

        $http.get(query).success(function (response) {
            tracks.push({'preview': response.tracks[0].preview_url});
        });
    });
    // here 
    console.log(artists);
});

Still, that solves it for artists, but then you'd need to do something similar if you need the tracks: as you have more then one request providing for that, you'd need to check the length of the tracks array and only if it has the complete length, like this:

$http.get('https://api.spotify.com/v1/search/?q=genre:pop&type=artist').success(function (data) {
    var items = data.artists.items;
    items.forEach(function(item){
        artists.push(item.name);
        artistids.push(item.id);
        var query = trackApi+item.id+'/top-tracks?country=SE'

        $http.get(query).success(function (response) {
            tracks.push({'preview': response.tracks[0].preview_url});
            if (tracks.length == items.length) { // all done
                console.log(artists, tracks);
            }
        });
    });
});

In a follow-up question (in comments) you explained you need this in your controller. You might look into $watch or variants of that method. If you need assistance with that, I would suggest to ask a new question.