art12345
art12345

Reputation: 59

Empty array in callback

I am using geocoder npm module to convert the address to lat,long. This API reads address from file google.csv using fast csv npm module after that result i.e addresses are passed to getLatLong function to convert to latitude and longitude respectively .Now when I pass latlongArray in getLatLong callback it goes empty.This is getting because of scope.Kindly suggest.

const geocoder   = require('geocoder');
const json2csv   = require('json2csv');
const fs         = require('fs');
const csv        = require('fast-csv'); 
var stream       = fs.createReadStream("google.csv");
var path         = './google.csv';
var async        = require('async');
var responseObj  = {};
var latlongArray = [];

var asyncArray   =[getCsvdata.bind(null, path, responseObj),
                   getLatLong.bind(null, responseObj)];
async.series(asyncArray ,function(err, result){
    if(err){
        console.log(err);
        return err;
    }   
     console.log(JSON.stringify(result));
})

function getCsvdata(path, responseObj, callback){
    var SuccessArray = [];
    var ErrorArray   = [];
    csv.fromPath(path)
        .on('data', function (data) {
            SuccessArray.push(data);
        })
        .on("error", function (data) {
            ErrorArray.push(data);
        })
        .on('end', function () {
            var ResultObject         = {Success: SuccessArray, ErrorList: ErrorArray};
            responseObj.adrressarray = ResultObject;
            callback(null, ResultObject);
        });
 }
function getLatLong(responseObj, callback){
    var responseArray = responseObj.adrressarray; 
    var geocodeArray  = responseArray.Success.slice(1);
    var geoLatLong   = geocodeArray.map(function(x) {
            var addressOfRow = x.toString();
            geocoder.geocode(addressOfRow, function (err, data) {
            if(err){
                return callback(err);
            }
            var latitude    = data.results[0].geometry.location.lat;
            var longitude   = data.results[0].geometry.location.lng;
            var address     = data.results[0].formatted_address;
            var obj         = [{"latitude":latitude,"longitude":longitude, "address":address}];
            latlongArray.push(obj);
        })
    }); 

    return callback(null, latlongArray);
}

Upvotes: 0

Views: 755

Answers (2)

Salketer
Salketer

Reputation: 15711

You'll want to use async.parallel. Since you are calling multiple geocoder.geocode. Since it is asynchronous, your function returns a value before they have ended.

function getLatLong(responseObj, callback){
    var responseArray = responseObj.adrressarray; 
    var geocodeArray  = responseArray.Success.slice(1);
    var geoLatLongFunctions   = geocodeArray.map(function(x) {
        return function(cb){
            var addressOfRow = x.toString();
            geocoder.geocode(addressOfRow, function (err, data) {
                if(err){
                     cb(err);
                }
                var latitude    = data.results[0].geometry.location.lat;
                var longitude   = data.results[0].geometry.location.lng;
                var address     = data.results[0].formatted_address;
                var obj         = [{"latitude":latitude,"longitude":longitude, "address":address}];
                cb(null,obj);
            });
         };
    }); 
    async.parallel(geoLatLongFunctions,callback);
}

Here, what I've done is make your geocodeArray.map return a function instead. And used async.parallel to execute them. Once all of them has finished, the callback will be called containing the results of all executions.

Upvotes: 1

trincot
trincot

Reputation: 350345

You are calling the callback too soon (synchronously), while the array is only populated later (asynchronously).

Make these changes:

function getLatLong(responseObj, callback){
    var latlongArray = []; // Define & initialise array here!
    var responseArray = responseObj.adrressarray; 
    var geocodeArray  = responseArray.Success.slice(1);
    geocodeArray.map(function(x) {
        var addressOfRow = x.toString();
        geocoder.geocode(addressOfRow, function (err, data) {
            if(err){
                return callback(err);
            }
            var latitude    = data.results[0].geometry.location.lat;
            var longitude   = data.results[0].geometry.location.lng;
            var address     = data.results[0].formatted_address;
            var obj         = [{"latitude":latitude,"longitude":longitude, "address":address}];
            latlongArray.push(obj);
            // Only call callback when array is complete
            if (latlongArray.length == geocodeArray.length) {
                callback(null, latlongArray);
            }
        })
    }); 
}

Upvotes: 1

Related Questions