Reputation: 14010
I have a set of directions that I'm trying to render in different colors. I request the directions from Google, but I'm not sure how to store the state so that when the routing results are returned I can render each one in the proper color.
So, as an example, I have this object:
{routes: [{start_lat : 0.0, start_lng : 0.0, end_lat : 1.0, end_lng : 1.0, color : "#ff0000"},
{start_lat : 1.0, start_lng : 1.0, end_lat : 2.0, end_lng : 2.0, color : "#00ff00"}]}
Here is my function:
directionsService = new google.maps.DirectionsService();
for(var i = 0; i < routes.length; i++){
var dir_request = {
origin : new google.maps.LatLng(routes[i]['start_lat'], routes[i]['stop_lng']),
destination : new google.maps.LatLng(routes[i]['end_lat'], routes[i]['end_lng']),
travelMode : google.maps.TravelMode.WALKING
};
directionsService.route(dir_request, function(result, status) {
if(status == google.maps.DirectionsStatus.OK){
// render with custom logic depending on which route this is here
}
})
}
How can I attach a state (for example, the index in the for loop) to each request so that it's accessible from the result processing function?
Upvotes: 0
Views: 117
Reputation: 43728
Some answers already have described how the problem can be solved with an explicit closure. Here's another example using Function.prototype.bind
.
directionsService.route(dir_request, (function(result, status) {
//the this keyword now refers to the correct route object
console.log(this);
if(status == google.maps.DirectionsStatus.OK){
// render with custom logic depending on which route this is here
}
}).bind(routes[i]));
EDIT:
Here's an efficient another way to do it without bind
. Having the scope-safe function inline in the loop is not efficient since a new one has to be created on every iteration.
It's better to create a function for that purpose and reuse it.
function createRouteCallback(route) {
return function (result, status) {
if(status == google.maps.DirectionsStatus.OK) {
// render with custom logic depending on which route this is here
//you can just use route here
console.log(route);
}
};
}
Then in the loop you can simply do:
directionsService.route(dir_request, createRouteCallback(routes[i]));
Upvotes: 1
Reputation: 388416
You need to make use of closure scoped variables to do that. When you try to use i
in the route callback function you are making use of a concept called as closures, where by a variable declared in a parent function will be accessible from an inner function.
But using closures in a loop has its own problems because the same instance of the closure variable will be shared between all the inner function created within the loop, so when the inner function is called you will get the last value assigned to the variable in the loop.
The solution here is to create a local closure inside the loop as shown below
directionsService = new google.maps.DirectionsService();
for (var i = 0; i < routes.length; i++) {
(function (idx) {
var dir_request = {
origin: new google.maps.LatLng(routes[idx]['start_lat'], routes[idx]['stop_lng']),
destination: new google.maps.LatLng(routes[idx]['end_lat'], routes[idx]['end_lng']),
travelMode: google.maps.TravelMode.WALKING
};
directionsService.route(dir_request, function (result, status) {
// the variable idx will refer to the array index for the current iteration
if (status == google.maps.DirectionsStatus.OK) {
// render with custom logic depending on which route this is here
}
})
})(i)
}
Upvotes: 1
Reputation: 17051
Marka is right. Unless something strange is happening, all of your function's variables are available inside the callback function(result,status)
. See here for an explanation and some examples. Since you know dir_request
when you create the callback, you can refer to it directly in the callback code. You should also be able to refer to i
if you need to access the routes
array.
If you have any trouble getting the value across, you can try adding a layer of indirection:
function makeCallback(dir_request) {
return function(result,status) {
//your code, and you can refer to dir_request
};
}
then call
directionsService.route(dir_request, makeCallback(dir_request));
I had to do that once in a Greasemonkey script in order to make sure the variables I needed were locked in when the function()
was created.
Upvotes: 0