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!

1
  • 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: stackoverflow.com/questions/14220321/… Commented Jul 22, 2015 at 15:42

3 Answers 3

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);
})
Sign up to request clarification or add additional context in comments.

Comments

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));
}

3 Comments

apparently I'm to jerky for this... copy&paste don't work :-( can you tell me how to use your snippet? Thanks so much!
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
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.
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.