Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript

target an item in an array returned by a function

Hey guys, I decided to revamp my JavaScript from my previous post found here https://teamtreehouse.com/forum/javascript-utc-time-format where Marcus Parsons and Dave McFarland helped me out.

Previously I have a function googleMapsApi that took in some data did some things and then called another function inside of it to do more work. I wanted to separate them out and make them more flexible, robust and reusable. so I came up with a new function geocoder which is to replace my googleMapsApi function. Geocoder returns an array but now I don't know how to call a specific part of that function for example

the below code is simply pseudo code

geocoder(input).array[0].output; 

here is my original go for the googleMapsApi

function googleMapsApi () {
        var url = "http://maps.googleapis.com/maps/api/geocode/json?address=" + zipcode + "&sensor=false";
        $.ajax(url, {
            data : null,
            type : "GET",
            success : function (response) {
                //3.2 Check to see if connection is successful
                if (response.status !== "OK") {
                    //3.2a If connection is unsucessful message
                    alert("Location Not Found");
                } else {
                    //3.2b If connection is successful, Convert user input to Latitude & Longitude
                    latitude = response.results[0].geometry.location.lat;
                    longitude = response.results[0].geometry.location.lng;
                    var zip = response.results[0].address_components[0].long_name;
                    var city = response.results[0].address_components[1].long_name;
                    var state = response.results[0].address_components[2].short_name;
                    var country = response.results[0].address_components[3].short_name;
                    loc = city + ", " + state;
                }
                //console.dir(response);
                forecast();
            }
        });
    }

Here is my geocoder

function geocoder (zipcode) {
            var url = "http://maps.googleapis.com/maps/api/geocode/json?address=" + zipcode + "&sensor=false";
            $.ajax(url, {
                data : null,
                type : "GET",
                success : function (response) {
                    //3.2 Check to see if connection is successful
                    if (response.status !== "OK") {
                        //3.2a If connection is unsucessful message
                        alert("Location Not Found");
                    } else {
                        //3.2b If connection is successful, Convert user input to Latitude & Longitude
                        var results = [
                            {
                                latlng : response.results[0].geometry.location.lat + "," + response.results[0].geometry.location.lng
                            },
                            {
                                "zip" : response.results[0].address_components[0].long_name,
                                "city" : response.results[0].address_components[1].long_name,
                                "state" : response.results[0].address_components[2].short_name,
                                "country" : response.results[0].address_components[3].short_name,
                                "loc" : "city" + ", " + "state"
                            }
                        ];
                    }
                    console.dir(results[0].latlng);
                    return results;
                }
            });
        }

1 Answer

Hugo Paz
Hugo Paz
15,622 Points

Hi John,

I did some changes to your code. Basically i added a callback function which is called when the ajax request receives the response.

This allows you to do something with the data, in this case I just did a console log of the response.

To call ii just go to your console and write geocoder(2000, callback) for example.

function callback(response){

        console.log(response);
    }




    function geocoder (zipcode, callback) {
        var url = "http://maps.googleapis.com/maps/api/geocode/json?address=" + zipcode + "&sensor=false";

        $.ajax(url, {
                data : null,
                type : "GET",
                success : function (response) {
                    //3.2 Check to see if connection is successful
                    if (response.status !== "OK") {
                        //3.2a If connection is unsucessful message
                        alert("Location Not Found");
                    } else {

                        var city = response.results[0].address_components[1].long_name,
                        state = response.results[0].address_components[2].short_name,
                        zip = response.results[0].address_components[0].long_name,
                        country = response.results[0].address_components[2].long_name;

                        //3.2b If connection is successful, Convert user input to Latitude & Longitude
                        var results = {
                            'latlng' : response.results[0].geometry.location.lat + "," + response.results[0].geometry.location.lng,
                            'location': {
                                'zip' : zip,
                                'city' : city,
                                'state' : state,
                                'country' : country,
                                'loc' : city + ", " + state
                            }
                        };

                        callback(results);

                    }

                }
            });
        }

Thanks! I tested it out appending various thins to the response like reponse.latlng and it outputs exactly as I would assume. So The reason I couldn't get this to work is because I needed a callback function which which would take the data out of the call so it could be used else where?

Here is the project in its current state https://github.com/johnweland/weather I am wanting to clean up the code quite a bit and write better more reusable code.

I thought I'd be spiffy and re-write my forecast function in the same manner you wrote the geocoder function. It didn't fly. perhaps I need more coffee.

function forecast (latlng, callback) {
        var apiKey = '9b176c486dcad0eaf7d6116ac46a0957';
        var url = 'https://api.forecast.io/forecast/';
        var data;
        //4.1 connect to Forecast.io API
        $.ajax(url + apiKey + "/" + latlng, {
                data : null,
                type : "GET",
                success: function(data) {
                    if (response.status !== "OK") {
                        alert("Forecast Error");
                    } else {
                        var dateTime = data.currently.time,
                        currentDate = new Date(dateTime * 1000),
                        weekday = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
                        dateTime = weekday[currentDate];

                        var results = {
                            'currently' : {
                                'temperature' : Math.round(data.currently.temperature),
                                'apparentTemperature' : Math.round(data.currently.apparentTemperature),
                                'dewPoint' : data.currently.dewPoint,
                                'humidity' : data.currently.humidity,
                                'precipIntensity' : data.currently.precipIntensity,
                                'precipProbability' : data.currently.precipProbability,
                                'cloudCover' : data.currently.cloudCover,
                                'barometricPressure' : data.currently.pressure,
                                'ozone' : data.currently.ozone,
                                'nearestStormBearing' : data.currently.nearestStormBearing,
                                'nearestStormDistance' : data.currently.nearestStormDistance,
                                'windBearing' : data.currently.windBearing,
                                'windSpeed' : data.currently.windSpeed,
                                'summary' : data.currently.summary,
                                'icon' : data.currently.icon
                            },
                            'daily' : {
                                'temperature' : Math.round(data.currently.temperature),
                                'apparentTemperature' : Math.round(data.daily.apparentTemperature),
                                'dewPoint' : data.daily.dewPoint,
                                'humidity' : data.daily.humidity,
                                'precipIntensity' : data.currently.precipIntensity,
                                'precipProbability' : data.daily.precipProbability,
                                'cloudCover' : data.daily.cloudCover,
                                'barometricPressure' : data.daily.pressure,
                                'ozone' : data.daily.ozone,
                                'nearestStormBearing' : data.daily.nearestStormBearing,
                                'nearestStormDistance' : data.daily.nearestStormDistance,
                                'windBearing' : data.daily.windBearing,
                                'windSpeed' : data.daily.windSpeed,
                                'summary' : data.daily.summary,
                                'icon' : data.daily.icon
                            }
                        };
                        callback(results);
                    }
                }
            });
        }

I got a cross-domain issue with this re-write. My original code was.

function forecast () {
        var apiKey = '9b176c486dcad0eaf7d6116ac46a0957';
        var url = 'https://api.forecast.io/forecast/';
        var data;
        //4.1 connect to Forecast.io API
        $.getJSON(url + apiKey + "/" + latlng + "?callback=?", function(data) {
            //console.dir(data);
            //4.2 Set variables for current weather
            dateTime = data.currently.time;
                    var currentDate = new Date(dateTime * 1000);
                    var currentDay = currentDate.getDay();
                    var weekday = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
                    dateTime =weekday[currentDay];
            temperature = Math.round(data.currently.temperature);
            apparentTemperature = Math.round(data.currently.apparentTemperature);
            dewPoint = data.currently.dewPoint;
            humidity = data.currently.humidity;
            precipIntensity = data.currently.precipIntensity;
            precipProbability = data.currently.precipProbability;
            cloudCover = data.currently.cloudCover;
            barometricPressure = data.currently.pressure;
            ozone = data.currently.ozone;
            nearestStormBearing = data.currently.nearestStormBearing;
            nearestStormDistance = data.currently.nearestStormDistance;
            windBearing = data.currently.windBearing;
            windSpeed = data.currently.windSpeed;
            summary = data.currently.summary;
            icon = data.currently.icon;
            $('#currently').html(   
                '<div class="col-sm-12">' + '<img src="img/icons/' + icon + '.png" />' + '<h1 class="text-center">' + loc + '</h1>' + '</div>' +
                '<div class="col-sm-12">' + '<p>' + dateTime + '</p>' + '</div>' +
                '<div class="col-sm-12">' + '<h2 class="text-center">' + temperature + '&deg;' + '</h2>' + '</div>' +
                '<div class="row">' +
                    '<div class=" col-xs-6 col-sm-3">' +
                        '<label>' + "Feels like" + '</label>' + 
                        '<p>' + apparentTemperature + ' &deg;' + '</p>' +
                    '</div>' +
                    '<div class="col-xs-6 col-sm-3">' +
                        '<label>' + "Humidity" + '</label>' + 
                        '<p>' + humidity + ' &#37;' + '</p>' +
                    '</div>' +
                    '<div class="col-xs-6 col-sm-3">' +
                        '<label>' + "Chance of Precipitation" + '</label>' + 
                        '<p>' + precipProbability + ' &#37;' + '</p>' +
                    '</div>' +
                    '<div class="col-xs-6 col-sm-3">' +
                        '<label>' + "Precipitation Intensity" + '</label>' + 
                        '<p>' + precipIntensity + ' inches per hour' + '</p>' +
                    '</div>' +
                '</div>' +
                '<div class="row">' +
                    '<div class="col-xs-6 col-sm-3">' +
                        '<label>' + "Wind Speed" + '</label>' + 
                        '<p>' + windSpeed + ' Mph' + '</p>' +
                    '</div>' +
                    '<div class="col-xs-6 col-sm-3">' +
                        '<label>' + "Direction" + '</label>' + 
                        '<p>' + windBearing + ' &deg;' + '</p>' +
                    '</div>' +
                    '<div class="col-xs-6 col-sm-3">' +
                        '<label>' + "Barometric Pressure" + '</label>' + 
                        '<p>' + barometricPressure + ' mBar' + '</p>' +
                    '</div>' +
                    '<div class="col-xs-6 col-sm-3">' +
                        '<label>' + "Ozone" + '</label>' + 
                        '<p>' + ozone + ' du' + '</p>' +
                    '</div>' +
                '</div>' +
                '<div class="row">' +
                    '<div class="col-sm-12">' +
                        '<label>' + "Summary : " + '</label>' + 
                        '<span> ' + summary + '</span>' +
                    '</div>' +
                '</div>'                                

            );

            //reset #fiveDayForecast
            $('#fiveDayForecast').html("");
            $('#fiveDayForecast').append('<h1>Your Five Day Forecast</h1>');


            //4.3 Set variables for daily weather
            var dailyData = data.daily.data;
            $.each(dailyData, function (key, value){
                //4.4 Skip current day and get next 5 days 
                if (key > 0  && key < 6) {
                    currentDate = new Date(this.time * 1000);
                    currentDay = currentDate.getDay();
                    weekday = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
                    var dailyIcon = dailyData[key].icon;
                    var dailySummary = dailyData[key].summary;
                    //console.log(weekday[currentDay]);
                    $('#fiveDayForecast').append('<div class="col-sm-2">' + '<label>' + weekday[currentDay] + '</label>' + '<img src="img/icons/' + dailyIcon + '.png" />' + '<p>' + dailySummary + '</p>' + '</div>');

                }       
            });
        });
    }

an update to my current work. Coffee has yielded some results, YAY coffee!

jQuery(document).ready(function ($) {

    //1. Set global variables
    var zipcode = "78130";
    var latlng;

    var loc;

    //2. Create functions
        function geoCB(response){
            console.log(response);
            forecast(response.latlng);
        }
        function forecastCB(forecast){
            console.log(forecast);
        }
        //2.1 geocoder function with Google Maps
        function geocoder (zipcode, callback) {
            var url = "http://maps.googleapis.com/maps/api/geocode/json?address=" + zipcode + "&sensor=false";
            $.ajax(url, {
                data : null,
                type : "GET",
                success : function (response) {
                    var city = response.results[0].address_components[1].long_name,
                    state = response.results[0].address_components[2].short_name,
                    zip = response.results[0].address_components[0].long_name,
                    country = response.results[0].address_components[2].long_name;

                    var results = {
                        'latlng' : response.results[0].geometry.location.lat + "," + response.results[0].geometry.location.lng,
                        'location': {
                            'zip' : zip,
                            'city' : city,
                            'state' : state,
                            'country' : country,
                            'loc' : city + ", " + state
                        }
                    }
                    geoCB(results);
                },
                error: function() {
                    consol.log("geocoder encountered an error");
                }
            });
        }
        //2.2 Forecast.io
        function forecast (latlng, callback) {
            var apiKey = '9b176c486dcad0eaf7d6116ac46a0957';
            var url = 'https://api.forecast.io/forecast/';
            var data;
            //2.2.1 connect to Forecast.io API
            $.ajax({
              url: url + apiKey + "/" + latlng,
              type: "GET",
              dataType: "jsonp",
              crossDomain: true,
              success: function(response) {
                forecast = response;
               forecastCB(forecast);
              },
              error: function() {
                console.log("This failed.");
              }
            });
        }

        geocoder(zipcode, geoCB);
});

I'd like to reuse the function callback (called geoCB and forecastCB in the above code). I'm not sure if I can create a single callback function that says if the response is coming from function A do this, if its coming from function B do this. then fix up function B enough to call in part of the response of callback (latlng) as of now I have to call forecast with in geoCB to pass that data in to forecast. its a WIP but a lot less code as of now then in the predecessor code.

Hugo Paz
Hugo Paz
15,622 Points

In the results object you could add an extra property, lets say type: and use its value on the call back function.

something like this:

function callback(response){

switch(response.type){

case 'type1':

//do things here
break

case 'type2':

//do other things here
break
}

}

Is that the best practice though? Having a single callback or having a call back defined for each function that requires it? Because now that I've got the data I need to build out my HTML to display it once build for forecast.currently and another block iterated in an each for the forecast.daily

My goal with this rewrite its to make it as modular and as clean as possible.