0

I'm using AngularJS to build a site where one of the functions is to present Billboard(it's a music chart) listings for a specified date. I want to present the songs in order, together with an image of the song.

First I'm calling this API:

http://billboard.modulo.site/

where I give a date and get a response of the top 10 songs for that date and data about each song.

The response from the Billboard API also includes a spotify id and I want to use that ID and call the Spotify Web API to get an image of that song, to complement the information I present about each song.

This is how it looks like in my controller:

var spotifyID = [];
$scope.spotifyImg = [];

musicService.getBillboard($scope.date).then(function(data){ //Response is top 10 songs for given date
        $scope.status = "";
        $scope.songlist = data;
        for (var i = 0; i < data.length; i++) {
            spotifyID[i] = data[i].spotify_id; //data[i].spotify_id returns the ID of the track, as given by the billboard API
        }
        $scope.getImages();
    });

$scope.getImages = function() {
    for (var i = 0; i < spotifyID.length; i++) {
        if(spotifyID[i] !== null) {
            musicService.getSpotify(spotifyID[i]).then(function(data){ 
                $scope.spotifyImg[i] = data.album.images[0].url; //returns the appropriate image from the Spotify Web API
        });
    }
    }
    console.log($scope.spotifyImg);
}

And in my view it would look something like this:

<div ng-repeat = "song in songlist">
    <div>{{ song.rank }}</div>
    <div>
        <img ng-src=" {{ spotifyImg[$index] }}"/>
    </div>
</div>

However, it does not work.

When I'm checking the $scope.spotifyImg array in the console, it is of length 11 and only has one element in index 10 and that is the image of the last song(that is the 10th song).

I'm a bit confused as to why the $scope.spotifyImg array only contains one element in index 10. Also why is the array of length 11 when the spotifyID is of length 10?

Any ideas of how I could solve this?

user3043462
  • 147
  • 1
  • 1
  • 6
  • try using `push ` method in place of `$scope.spotifyImg[i]` and dnt use for thats why you are getting last element in array. use do while or recursive call for it. like once you get data for first then call second – Jayant Patil Mar 29 '17 at 07:32
  • In `$scope.getImages` function, please `console.log` the variable `spotifyID` and post the results. – Nicolae Olariu Mar 29 '17 at 07:35

4 Answers4

2

The problem is that getSpotify is run asynchronous, when the responses to these calls come in, i is probably set to spotifyID.length - 1 which means that all callback functions set the $scope.spotifyImg[spotifyID.length - 1] element.

Try this:

$scope.spotifyImg = [];

musicService.getBillboard($scope.date).then(function(data){ 
        $scope.status = "";
        $scope.songlist = data;
        for (var i = 0; i < data.length; i++) {
            $scope.getImage(data[i].spotify_id, i);
        }
});

$scope.getImage = function(id, index) {
  musicService.getSpotify(id).then(function(data){ 
      $scope.spotifyImg[index] = data.album.images[0].url;
  });
}
Titus
  • 20,544
  • 1
  • 19
  • 29
1

create separate function and put the content of for loop inside that function and call that function inside the loop

$scope.getImages = function() {
    for (var i = 0; i < spotifyID.length; i++) {
        if (spotifyID[i] !== null) {
            sampleFunc(i);
        }
    }
}

function sampleFunc(i) {
    musicService.getSpotify(spotifyID[i]).then(function(data) {
        $scope.spotifyImg[i] = data.album.images[0].url; //returns the appropriate image from the Spotify Web API
    });
}

I think reason you get only last index of an array is when you are calling promise inside loop, loop does't wait until the promise returns. it just keep executing.At the time promise returns loop is executed and it;s getting last index of the array. That's why you need to separately call the promise from for loop

Sachila Ranawaka
  • 28,742
  • 4
  • 48
  • 69
  • stil the `console.log($scope.spotifyImg)` will log synchron, consquently the array maybe has no definition at the `console-time`. But the code should solve the main-propblem :-) – DomeTune Mar 29 '17 at 07:41
  • @DomeTune you are right. i should remove the console log. if i put it inside promise then it will print multiple time – Sachila Ranawaka Mar 29 '17 at 07:44
1

You can use IIFE

(function(i){
        musicService.getSpotify(spotifyID[i]).then(function (data) {

          $scope.spotifyImg[i] = data.album.images[0].url;
        });
 })(i)

So,your getImages function should be like this.

$scope.getImages = function () {
for (var i = 0; i < spotifyID.length; i++) {
    if (spotifyID[i] !== null) {
        (function(i){
             musicService.getSpotify(spotifyID[i]).then(function (data) {

                $scope.spotifyImg[i] = data.album.images[0].url;
             });
        })(i)

    }
}

}

Community
  • 1
  • 1
RIYAJ KHAN
  • 13,830
  • 5
  • 27
  • 48
0

Try using this code

Js code

  var spotifyID = [];
      $scope.spotifyImg = [];
      musicService.getBillboard($scope.date).then(function(data) { //Response is top 10 songs for given date
        $scope.status = "";
        $scope.songlist = data;
        for (var i = 0; i < data.length; i++) {
          spotifyID[i] = data[i].spotify_id; //data[i].spotify_id returns the ID of the track, as given by the billboard API
        }
        $scope.getImages(0);
      });


      $scope.getImages = function(index) {
        if (index == spotifyID.length) {
          return;
        }

        musicService.getSpotify(spotifyID[index]).then(function(data) {
          $scope.spotifyImg[index] = data.album.images[0].url; //returns the appropriate image from the Spotify Web API

          // call recursive here
          $scope.getImages(index++);

        });
      }
    }

call your getimages function recursively so that will add you images in array.

Jayant Patil
  • 1,326
  • 2
  • 9
  • 17