0

I have the below JavaScript function to grab a country code and it's geometry as per name from a JSON object. So that when the country name is selected, the appropriate country border is added and the country code stored.

The border adds perfectly and the code is obtained within the function

However, note that I call the variable code outside of the function and when I do so it returns undefined. How can I ensure the code is recognisable outside of this function for use in others?

I'm totally lost at this point as I feel like I've tried everything!

  • Creating the variable outside of the function
  • Returning it
  • Calling the function again
  • Trying the answers of endless Stackoverflow posts ....

I just feel I'm at a loss now

var code;


$("#innerSelect").on("change", () => {     //Handles changing the country select.
    addCountryBorder($("#innerSelect").val());  /* Calls function that adds country border to map */
    countryInfo($("#innerSelect").val());

    $.ajax({                             
        url: "libs/php/getCoordsFromCountryName.php",
        type: "GET",
        dataType: "json",
        data: {
            countryName: $("#innerSelect").val(),
            
        },
        success: function(result) {

           
            if (result.status.name == "ok") {
                map.panTo(new L.LatLng(result["data"][0]["geometry"]["lat"] , result["data"][0]["geometry"]["lng"]))
            }
        
        },
        error: function(jqXHR, textStatus, errorThrown) {
           console.log(errorThrown);
        }
            

})
});

/* Function responsible for adding border to a given country and grabbing country code*/
function addCountryBorder(countryName) {

    $.ajax({
        url: "assets/geojson/countryBorders.geo.json",
        type: "GET",
        dataType: "json",
        data: {
            
        },
        success: function(result) {
            let features = result["features"];

            let countryFeature = findFeatureFromName(countryName);
            code = JSON.stringify(countryFeature.properties.iso_a2)
            
            console.log(code)
            return code;
            
            if (!countryFeature) {
                return;
            }
            if (border) {
                map.removeLayer(border);
            }
            border = new L.geoJSON(countryFeature["geometry"], {
                style: {
                color: "#006600",
                
                }
            }
                ).addTo(map);
            
            map.panTo(border.getBounds().getCenter());
            map.fitBounds(border.getBounds());

        console.log(countryFeature)
        },
        error: function(jqXHR, textStatus, errorThrown) {
            console.log(errorThrown);
        }
    })
}


console.log(code)

I then want to call code in a new function to pass as a parameter for an API call. See below idea of next function

function countryInfo() {

    $.ajax({
        url: "assets/php/countryInfo.php",
        type: 'POST',
        dataType: 'json',
        data: {
            country: code,
        },
        success: function(result) {
            if (result.status.name == "ok") {
                coords.push({currencyCode: result.data[0].currencyCode});
                
                let formattedPopulation = result['data'][0]['population'].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
                let formattedArea = Math.round(result['data'][0]['areaInSqKm']).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");

                $('#continent').html(result['data'][0]['continentName']);
                $('#capital').html(result['data'][0]['capital']);
                $('#countryName').html(result['data'][0]['countryName']);
                $('#population').html(formattedPopulation);
                $('#currencyCode').html(result['data'][0]['currencyCode']);
                $('#area').html(formattedArea);

                currencyConverter();
            }
        },
        error: function(jqXHR, textStatus, errorThrown) {
            console.log(jqXHR)
            console.log(textStatus)
            console.log(errorThrown)
        }
    });
}

The information obtained from this call will then be displayed in a modal

  • First of all, I don't see the function being called before that console.log would execute. Secondly, even if you do call addCountryBorder first, the result of the function is returned asynchronously, so the function returns first and the call back that puts the value into code happens later. – kshetline Oct 26 '22 at 15:50
  • @kshetline sorry I included where it is called now – javascript_bewildered934 Oct 26 '22 at 15:51
  • var is function scoped. You are trying to assign the variable in a different function. Change your global variable to `let code;` – Steve Oct 26 '22 at 15:55
  • Does this answer your question? [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) - The bottom line is that the whole operation is asynchronous. Your best (least confusing) bet by the way is to refactor the code to use `async`/`await` and **no** callbacks whatsoever (also no `then`). Then it should be very clear to follow the flow. `$.ajax` has a promise interface so you can `await` it too. – CherryDT Oct 26 '22 at 16:19
  • Here is how a refactored version of the code could look: https://gist.github.com/CherryDT/7e95c6b80f1a353d3270ff775137e767 - However, I realized now, it's not clear at what point you want to use `code` in the first place. Because it is only ever set if your dropdown is changed - so you can't log it at the start before that even happens! – CherryDT Oct 26 '22 at 16:29
  • @CherryDT sorry, I added extra detail as to how exactly I want to use ```code``` – javascript_bewildered934 Oct 26 '22 at 16:32

1 Answers1

0

Get rid of the outer/global variable and use a callback like so:

/* Function responsible for adding border to a given country and grabbing country code*/

function addCountryBorder(countryName, cb) {

    $.ajax({
        url: "assets/geojson/countryBorders.geo.json",
        type: "GET",
        dataType: "json",
        data: {
            
        },
        success: function(result) {
            let features = result["features"];

            let countryFeature = findFeatureFromName(countryName);
            let code = JSON.stringify(countryFeature.properties.iso_a2)
            
            console.log(code) // get rid of early return
            
            if (!countryFeature) {
                return cb(null, {code});
            }
            if (border) {
                map.removeLayer(border);
            }
            border = new L.geoJSON(countryFeature["geometry"], {
                style: {
                color: "#006600",
                
                }
            }
                ).addTo(map);
            
            map.panTo(border.getBounds().getCenter());
            map.fitBounds(border.getBounds());

            console.log(countryFeature)
            cb(null, {countryFeature,code})
        },
        error: function(jqXHR, textStatus, errorThrown) {
            cb({jqXHR, textStatus, errorThrown}
        }
    })
}

then call it with:

addCountryBorder('some country name', (err, result) => {
    // check if err is not null
    // result will be {code, countryFeature}
});

the above is equivalent to:

const cb =  (err, result) => {

    // check if err is not null
    // result will be {code, countryFeature}

    console.log('result is:', result);
};


// pass the callback cb
addCountryBorder('some country name', cb);
Alexander Mills
  • 90,741
  • 139
  • 482
  • 817