0

I have a JSON object with some entries (Appointments) each thereof an "location id". Then I loop trough these entries and emit a request to my nodeJS server by socketIO to get data from document with the location id.

At the end I need an array with the data of lat/lng to create some marker on a map.

Here is the code:

//controller for showing map
.controller('MapCtrl', function($scope, socket){

    socket.emit('getApp', staticUserid);

        socket.on('getApps', function (appdata) {
                var locArr = [];
                for (var i = 0; i < appdata.length; i++) {
                    if (appdata[i].locationid != '') {
                        locArr.push(appdata[i].locationid);
                    }
                }
                var LatLngArr = [];
                for (var j = 0; j < locArr.length; j++) {
                    socket.emit('getLocation', locArr[j]);
                    socket.on('getLoc', function (locData) {
                        console.log('received lat/lng: ' + locData.lat + '/' + locData.lng);
                        if (!LatLngArr[j]) LatLngArr[j] = []
                        LatLngArr[j][0] = locData.lat;
                        LatLngArr[j][1] = locData.lng;
                    });
                }
                //console.log('test:'+LatLngArr[0][0]);
        });

    var newMarkers = [[52.549678, 13.3879516],[52.5442992, 13.352809],[52.5186283,13.3761181]]; // this should be the generated array
    var newCenter = [52.549678, 13.3879516];
    createMap(newCenter,newMarkers);

})

The problem is, that the var LatLngArr isn't defined out of the...

socket.on('getLoc', function (locData)

It would be very nice if somebody can help me :-)

Thanks so much!

tier1
  • 6,303
  • 6
  • 44
  • 75
km65
  • 21
  • 9
  • Async , async, async. When you understand that you can ONLY use an async result in the callback which delivers it (not outside that callback), then you will understand what you have to do to fix your code. FYI, this is a common issue as I see questions like this many times a day here. This is one of the more canonical answers on the topic: http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-asynchronous-call – jfriend00 Jul 22 '15 at 15:42

3 Answers3

1

If you can use Promises

.controller('MapCtrl', function($scope, socket){

    socket.emit('getApp', staticUserid);

    socket.on('getApps', function (appdata) {
        var locArr = [];
        for (var i = 0; i < appdata.length; i++) {
            if (appdata[i].locationid != '') {
                locArr.push(appdata[i].locationid);
            }
        }
        var LatLngArr = [];
        var promises = [];
        for (var j = 0; j < locArr.length; j++) {
            promises[j] = (function(captured_j) {
                return new Promise(function(resolve, reject) {
                    socket.emit('getLocation', locArr[captured_j]);
                    socket.on('getLoc', function (locData) {
                        console.log('received lat/lng: ' + locData.lat + '/' + locData.lng);
                        if (!LatLngArr[captured_j]) LatLngArr[captured_j] = []
                        LatLngArr[captured_j][0] = locData.lat;
                        LatLngArr[captured_j][1] = locData.lng;
                        resolve({index: captured_j, result: LatLngArr[captured_j]});
                    });
                });
            }(j));
        }
        Promise.all(promises).then(function(arr) {
            // ******************************************
            // ******************************************
            // arr is an array of {index: #, result [lat, lng]} - but you can also use LatLngArr
            // ******************************************
            // ******************************************
        });
    });
    var newMarkers = [[52.549678, 13.3879516],[52.5442992, 13.352809],[52.5186283,13.3761181]]; // this should be the generated array
    var newCenter = [52.549678, 13.3879516];
    createMap(newCenter,newMarkers);
})
Jaromanda X
  • 53,868
  • 5
  • 73
  • 87
0

try this

for (var j = 0; j < locArr.length; j++) {
    (function(captured_j) {
        socket.emit('getLocation', locArr[captured_j]);
        socket.on('getLoc', function (locData) {
            console.log('received lat/lng: ' + locData.lat + '/' + locData.lng);
            if (!LatLngArr[captured_j]) LatLngArr[captured_j] = []
            LatLngArr[captured_j][0] = locData.lat;
            LatLngArr[captured_j][1] = locData.lng;
            //
            // the required result
            //
            if (j === 0) {
                console.log('test:'+LatLngArr[0][0]);
            }
            //
        });
    }(j));
}
Jaromanda X
  • 53,868
  • 5
  • 73
  • 87
  • apparently I'm to jerky for this... copy&paste don't work :-( can you tell me how to use your snippet? Thanks so much! – km65 Jul 22 '15 at 14:35
  • Yes I did this and there is no error. But this way I can't access to the array LatLngArr at the line of console.log('test').... and get this error: TypeError: Cannot read property '0' of undefined – km65 Jul 22 '15 at 14:47
  • I think you didn't understand my problem... I need this array outside the socket.on function because this one loops several times. and the createMap function should be called only one time with a ready filled array. You know what I mean? The log is only an example to test, if the arr is defined there. – km65 Jul 22 '15 at 15:04
0

The reason why your code fails is because of the asynchronous nature of the line:

socket.on('getLoc', function (locData)

So LatLngArr actually is defined when you register the callback, but it is not anymore at the time the callback is called. The reason for that is that JavaScript uses Closures.

You may have a look at this thread: How do JavaScript closures work?

Hence you have to wrap it in an IIFE. This way the function is executed immediately such that the value of j behaves as you intended, because it is not longer referring to the j of the outer scope.

Edit: A very nice explanation can be found in Item 13 of David Hermann's "Effective Javascript" – a book I totally can recommend. If you have problems understanding it, a look at this thread may help.

Community
  • 1
  • 1
philonous
  • 3,621
  • 3
  • 27
  • 24