Arrays returning undefined for API calls (spotify

2019-09-20 19:01发布

问题:

Hey guys I'm working on a Javascript web app which uses Spotify API. I'm trying to return the top 5 albums of a given artist in a table. So far I got the API calls working and they return a table which displays ALL the albums of an artist in no particular order. I'm trying to shrink the table to the top 5 albums based on "popularity" which is the fifth column of the table.

 var popsort = new Array(new Array());
    var count = 0;

    $(document).ready(function () {
    $("#searchbutton").click(function () {
        search();
    });
    ,
    function search() {
        var query1 = document.getElementById('querybox').value;
        $.get("https://api.spotify.com/v1/search?q=" + query1 + "&type=artist", function (data) {
            //alert(data.artists.items[0].id);
            getSeveralAlbums(data.artists.items[0].id);
        });
    }

    function getSeveralAlbums(artistid) {
        //alert(artistid);
        $.getJSON("https://api.spotify.com/v1/artists/" + artistid + "/albums?album_type=album",
        function (json) {
            //bob = json;
            //console.log(json);
            console.log(json.items.length);
            for (var i = 0; i < json.items.length; i++) {
                createArray(json.items[i].href);
            }
            //console.log(count);
            popsort.sort(sortPopularity);
            //getAlbumInfo(json.items[i].href);
            getAlbumInfo(popsort);
        });
    }

    function getAlbumInfo(popsort) {
        var tr;
        console.log(popsort);
        // i<json.length
        // Sort the array first by popularity. And then create a for loop and print the first five. 
        tr = $('<tr/>');
        for (var i = 0; i < 5; i++) {
            tr.append("<td>" + popsort[i][0] + "</td>"); // Album Name
            tr.append("<td>" + popsort[i][1] + "</td>"); // Artist Name
            tr.append("<td>" + popsort[i][2] + "</td>"); // Release Date
            tr.append("<td>" + popsort[i][3] + "</td>"); // Number of Tracks
            tr.append("<td>" + popsort[i][4] + "</td>"); // Popularity
        }
        $('table').append(tr);

    }

    function createArray(albumhref) {
        //console.log(albumhref);
        $.getJSON(albumhref,
            function (json) {
                // i<json.length
                // Sort the array first by popularity. And then create a for loop and print the first five. 
                console.log(count);
                popsort[count][0].push(json.name);
                popsort[count][1].push(json.artists[0].name);
                popsort[count][2].push(json.release_date);
                popsort[count][3].push(json.tracks.total);
                popsort[count][4].push(json.popularity);
                ++count;
                //alert("table compiled");
                //alert("Table done");
            });
    }

    function sortPopularity(a, b) {
        if (a[4] === b[4]) {
            return 0;
        }
        else {
            return (a[4] < b[4]) ? -1 : 1;
        }
    }

});

I use the click function at the top to get the artist name from a textbox, pass that into the "search" function which returns an artistid. I pass this artistid into the "getSeveralAlbums" functions. The json call in this function returns the hrefs to all the albums of a specific artist which I want to store in an 2D array along with the popularity. My "sortPopularity" function near the bottom will ideally sort this array by the fifth element which is "popularity" and then I plan to pass this sorted array (popsort) into the getAlbumInfo function which has a for loop printing 5 times, which will ideally print the first five elements of the popsort array. After sorting this will ideally be the top 5 most popular albums of an artist.

When I try to run this program, it returns an error undefined for both popsort[count][0].push(json.name); in the createArray function, and it returns an error undefined for tr.append("<td>" + popsort[i][0] + "</td>"); in the getAlbumInfo function. What am I doing wrong?

Update: (new code)

var popsort = new Array(new Array());
var count = 0;
var looopCount = 0;

$(document).ready(function () {

$("#searchbutton").click(function () {
    search();
});

function search() {
    var query1 = document.getElementById('querybox').value;
    $.get("https://api.spotify.com/v1/search?q=" + query1 + "&type=artist", function (data) {
        getSeveralAlbums(data.artists.items[0].id);
    });
}

function getSeveralAlbums(artistid) {
    $.getJSON("https://api.spotify.com/v1/artists/" + artistid + "/albums?album_type=album",
    function (json) {
        console.log(json.items.length);
        looopCount = json.items.length;
        for (var i = 0; i < json.items.length; i++) {
            createArray(json.items[i].href);
        }
    });
}

function getAlbumInfo(popsort) {
    var tr;
    // Sort the array first by popularity. And then create a for loop and print the first five. 
    tr = $('<tr/>');
    for (var i = 0; i < 5; i++) {
        tr.append("<td>" + popsort[i][0] + "</td>"); // Album Name
        tr.append("<td>" + popsort[i][1] + "</td>"); // Artist Name
        tr.append("<td>" + popsort[i][2] + "</td>"); // Release Date
        tr.append("<td>" + popsort[i][3] + "</td>"); // Number of Tracks
        tr.append("<td>" + popsort[i][4] + "</td>"); // Popularity
    }
    $('table').append(tr);

}

function createArray(albumhref) {
    $.getJSON(albumhref,
        function (json) {
            if (popsort.length <= count) {
                popsort.push(new Array());
            }
            // Sort the array first by popularity. And then create a for loop and print the first five. 
            popsort[count].push(json.name);
            popsort[count].push(json.artists[0].name);
            popsort[count].push(json.release_date);
            popsort[count].push(json.tracks.total);
            popsort[count].push(json.popularity);
            ++count;
            batchSort(--looopCount);
        });
}

function sortPopularity(a, b) {
    if (a[4] === b[4]) {
        return 0;
    }
    else {
        return (a[4] > b[4]) ? -1 : 1;
    }
}

function batchSort(i) {
    if (i <= 0) {
        popsort.sort(sortPopularity);
        getAlbumInfo(popsort);
    }
}
});

回答1:

First is that you are accessing undefined key of popsort in createArray(), use .push() instead. Second, the getAlbumInfo(sortPopularity); function is already called while the first $.getJSON(albumhref, fn...); reponse has not yet returned thus leaving you with an empty array to access. Tht is why you get an undefined return when accessing the popsort

What I would do is I will create a descending counter and add it to the createArray's $.getJSON() callback, like this:

var popsort = new Array(new Array());
    var count = 0;
    var looopCount = 0;

    function getSeveralAlbums(artistid) {
        $.getJSON("https://api.spotify.com/v1/artists/" + artistid + "/albums?album_type=album",
        function (json) {
            console.log(json.items.length);
            looopCount = json.items.length
            for (var i = 0; i < json.items.length; i++) {
                createArray(json.items[i].href);
            }
            // call both popsort.sort(sortPopularity); and getAlbumInfo(popsort); after all the data is loaded to popsort, not here.
        });
    }

    function createArray(albumhref) {
        $.getJSON(albumhref,
            function (json) {
                if (popsort.length <= count) {
                    // if the length of popsort is less than count, it means that that index(count) is not yet present in popsort
                    // push to add an item with index=count to popsort
                    popsort.push(new Array());
                }
                popsort[count].push(json.name);
                popsort[count].push(json.artists[0].name);
                popsort[count].push(json.release_date);
                popsort[count].push(json.tracks.total);
                popsort[count].push(json.popularity);
                ++count;

                batchSort(--looopCount);
            });
    }

    function batchSort(i) {
        if (i <= 0) {
            popsort.sort(sortPopularity);
            getAlbumInfo(popsort);
        }
    }

});

function getAlbumInfo(popsort) {
    for (var i = 0; i < 5; i++) {
        tr.append("<tr><td>" + popsort[i][0] + "</td>"); // Album Name
        tr.append("<td>" + popsort[i][1] + "</td>"); // Artist Name
        tr.append("<td>" + popsort[i][2] + "</td>"); // Release Date
        tr.append("<td>" + popsort[i][3] + "</td>"); // Number of Tracks
        tr.append("<td>" + popsort[i][4] + "</td></tr>"); // Popularity
    }

}

Haven't tested it though, but that's the thought.. Hope it helped.