0

I'm trying to make a Google Places API + Instagram API application. A user enters a location and keyword and results and associated Instagram photos render. The results' lat/lng coordinates are stored in an array and are then concatenated to an Instagram URL JSON-P response. This URL is appended to the HTML as a script tag and later removed when the photos are rendered. However I am encountering an error:

Uncaught TypeError: Cannot read property 'removeChild' of null.

Here is the Javascript. This JS is a simpler version of my application (locations are pre-defined).

document.addEventListener('DOMContentLoaded', function () {

var sanFran = {lat: 37.7700623, lng: -122.4463697};
var losAngeles = {lat: 34.0482814, lng: -118.2479595};
var newYork = {lat: 40.7484444, lng: -73.9878441};
var chicago = {lat: 41.8503659, lng: -87.7064438};
var boston = {lat: 42.3134791, lng: -71.1271966};

var locationArray = [sanFran, losAngeles, newYork, chicago, boston];

function loop(array){
    for(var i = 0; i < array.length; i++){
        var lat = array[i].lat;
        var lng = array[i].lng;
        var accessToken = '249457765.1fb234f.adc28edf9d7f4ad2ad281752445eac86';
        var url = 'https://api.instagram.com/v1/media/search?lat=' + lat + '&lng=' + lng + '&distance=100' + '&access_token=' + accessToken + '&callback=?';
        getJSONP(url, success, i);
    }
}

function getJSONP(url, success, i) {

        var ud = '_' + +new Date,
        script = document.createElement('script'),
        body = document.getElementsByTagName('body')[0] 

        //callback for JSON-P response
        window[ud] = function(data) {

            script.parentNode.removeChild(script);
            success && success(data, i);
        };
        console.log(url);
        body.appendChild(script);
        script.src = url.replace('callback=?', 'callback=' + ud);


}

function success(response, i){
        var results = document.getElementById("results");
        var responseLength = response.data.length;
        var totalResults = 5;

        //cap photos to 5 or less
        responseLength = totalResults;

        for(var j = 0; j < responseLength; j++){
            var img = document.createElement("IMG");
            img.src = response.data[j].images.thumbnail.url;
            results.appendChild(img);
            img.id = "img";
        }               
}
loop(locationArray);
});

Here is the HTML:

<!DOCTYPE html>
<html>
  <head>
    <title>Places and Instagram App</title>
<meta name="viewport" content="initial-scale=1.0">
<meta charset="utf-8">
<link href="style1.css" rel="stylesheet">
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCxUwNycYzt3GGO0FvZGYJd3zUQQDEFal8&libraries=places"></script>
<script src="stack.js"></script>

  </head>
  <body>
    <h1>Instagram Photos</h1>
    <div id = "results">
    </div>
  </body>
</html>

In theory, if the application was working properly, a total of 25 photos would render.

Note: I cannot use JQuery or any external libraries/frameworks. I also used this solution as a reference: Failed to execute 'removeChild' on 'Node', however it did not work for me (error in console disappeared but photos still wouldn't render). Also, when console logging the [array item] in the window[ud] variable, it looks like the items are not passing in the correct order. Thanks for the help.

Community
  • 1
  • 1
hewp
  • 5
  • 3
  • The items are not passing in the correct order because the AJAX request are asynchronous, so if you want to have them in order you could create an array to store all the results and use the index to store the data retrieved from the API in the array of results – Rodrigo Juarez Apr 27 '16 at 23:32

2 Answers2

0

I changed a little bit your code, first off, now you pass the array of locations to the function getLocationPhotos(), this method will call the method getLocation(), there you will retrieve all the photos from Instagram. One of the problems that you were having is that you were hardcoding the responseLength of the request, when some request did not have any response at all. For example, one of the responses from your requests

/**/ _1461800988408({"meta":{"code":200},"data":[]})

Also, each of the requests is executed after the end of the previous one, so you have all your images in order. Here is the new code that I made:

document.addEventListener('DOMContentLoaded', function () {

var sanFran = {lat: 37.7700623, lng: -122.4463697};
var losAngeles = {lat: 34.0482814, lng: -118.2479595};
var newYork = {lat: 40.7484444, lng: -73.9878441};
var chicago = {lat: 41.8503659, lng: -87.7064438};
var boston = {lat: 42.3134791, lng: -71.1271966};

var locationArray = [sanFran, losAngeles, newYork, chicago, boston];

function getLocationPhotos(locations){
    if(locations.length) getLocation(locations, successCallback, 0);
}

function getLocation (locations, successCallback, index) {
        var lat = locations[index].lat;
        var lng = locations[index].lng;
        var accessToken = '249457765.1fb234f.adc28edf9d7f4ad2ad281752445eac86';
        var url = 'https://api.instagram.com/v1/media/search?lat=' + lat + '&lng=' + lng + '&distance=100' + '&access_token=' + accessToken + '&callback=?';
        getJSONP(url, function (response, index) {
            successCallback(response, index);
            if (locations.length - 1 > index) getLocation(locations, successCallback, index + 1);
        }, index);
}

function getJSONP(url, successCallback, index) {

        var ud = '_' + +new Date(),
        script = document.createElement('script'),
        body = document.getElementsByTagName('body')[0]; 

        //callback for JSON-P response
        window[ud] = function(data) {

            script.parentNode.removeChild(script);
            if(!data) return errorCallback(index, successCallback);
            if(successCallback) successCallback(data, index);
        };
        console.log(url);
        body.appendChild(script);
        script.src = url.replace('callback=?', 'callback=' + ud);


}

function errorCallback(index, afterEndsCallback) {
  console.log('Your index' + index + 'had a problem retrieving the data');
  afterEndsCallback([], index);
}

function successCallback(response, i){
        var results = document.getElementById("results");
        var responseLength = response.data.length;

        for(var j = 0; j < responseLength; j++){
            var img = document.createElement("IMG");
            img.src = response.data[j].images.thumbnail.url;
            results.appendChild(img);
            img.id = "img";
        }               
}
getLocationPhotos(locationArray);
});

Link to the code

Rodrigo Juarez
  • 873
  • 1
  • 7
  • 17
-1

It works. Place the script at the end or execute it on window's onload.

Gabriel
  • 2,170
  • 1
  • 17
  • 20