JavaScript Objects - Object values getting undefined after constructing - javascript

I am trying to create an object that handles Google Maps Api as following:
function GoogleMap(container, mapOptions) {
this.Container = container;
this.Options = mapOptions;
this.Map = new google.maps.Map(document.getElementById(this.Container), this.Options);
// Direction
this.DirectionService = new google.maps.DirectionsService();
this.DirectionRenderer = new google.maps.DirectionsRenderer();
this.DirectionRenderer.setMap(this.Map);
this.DirectionId = 0;
this.DirectionResponse = new Array();
this.DrawDirectionDriving = drawDirectionDriving;
}
and the drawDirectionDriving function is like this:
function drawDirectionDriving(start, end) {
var request = {
origin: start,
destination: end,
travelMode: google.maps.TravelMode.DRIVING
};
this.DirectionService.route(request,
function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
this.DirectionRenderer.setDirections(response);
this.DirectionResponse[this.DirectionId] = response;
this.DirectionId++;
}
else {
alert("Error during drawing direction, Google is not responding...");
}
}
);
}
and in somewhere, I am using the object like this:
var myGoogleMap;
function MapInit() {
myGoogleMap = new GoogleMap("divMap", myMapOptions);
myGoogleMap.DrawDirectionDriving("İstanbul", "Ankara");
}
The Google Map is shown on my browser, there is no problem in constructing the object but error in DrawDirectionDriving function.
When I create a breakpoint on this line: " myGoogleMap.DrawDirectionDriving("İstanbul", "Ankara");" the "DirectionRenderer" seems constructed, but after this line (after the "Draw" method) the DirectionRenderer object seems null (undefined) so it outs en error like this "couldn't get setDirections properties it is null bla bla..."
Could you please give me a hand?
Thanks in advance...

The this keyword does point to something else in the route callback function. It's DirectionRenderer property resolves to null/undefined, and getting the setDirections property from that will cause the exception.
Use a dereferencing variable:
function drawDirectionDriving(start, end) {
var request = {
origin: start,
destination: end,
travelMode: google.maps.TravelMode.DRIVING
};
var that = this;
this.DirectionService.route(request,
function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
that.DirectionRenderer.setDirections(response);
that.DirectionResponse[this.DirectionId] = response;
that.DirectionId++;
// ^^^^ points to the GoogleMap instance
}
else {
alert("Error during drawing direction, Google is not responding...");
}
}
);
}

Related

Google Maps API asynchronous

I'm currently working with the Google Maps API. I use the globalFunction when user click on some button. The "calcRoad" function generate the road by using the Google Maps API, and then "Myfunction" use the data from "calcRoad" to do some calculation.
My problem is that right now "Myfunction" doesn't wait "calcRoad" to end before starting. I asume that some of the Google API requests are asynchronous but I can't access the code behind it.
How could I forced "Myfunction" to wait until "calcRoad" is done ?
function globalFunction(){
calcRoad(true,latitude, longitude);
Myfunction();
}
function calcRoad(bool,lat,long) {
marker.setVisible(false);
var date = new Date();
// Add a waypoint
if(bool){
var tampon = new google.maps.LatLng(lat,long);
waypoints.push({
location: tampon,
stopover:false
});
}
var request = {
origin: departure_place.geometry.location,
destination: arrival_place.geometry.location,
travelMode: google.maps.TravelMode[mode],
waypoints: waypoints,
avoidHighways: false,
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
}
});
}
PS: I tried to use some setTimeout before calling "Myfunction" and it is working but as I don't know how long will the "calcRoad" take to finish (depending on users' parametres) I can't use setTimeout.
I hope that I'm clear with my probleme, thanks in advance for your help.
You should add a callback parameter in your calcRoad function :
function globalFunction(){
calcRoad(true,latitude, longitude, Myfunction);
}
function calcRoad(bool,lat,long, cb) {
marker.setVisible(false);
var date = new Date();
// Add a waypoint
if(bool){
var tampon = new google.maps.LatLng(lat,long);
waypoints.push({
location: tampon,
stopover:false
});
}
var request = {
origin: departure_place.geometry.location,
destination: arrival_place.geometry.location,
travelMode: google.maps.TravelMode[mode],
waypoints: waypoints,
avoidHighways: false,
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
cb && cb(); // Check if "cb" callback function is defined and execute it
}
});
}
Something like this should work !

Remove rendered direction routes on google map

I try to render direction route on google map and my issue was, when I am try to get another direction route previously rendered route not clear. I want to know how I reset rendered route on the map.
Here my code.
function direction(dest, lat, lng) {
$('#direction').slideUp();
$('#results').slideDown();
$('#dest-direction').val(dest);
$('#direction-form').submit(function () {
var ori = $('#origin-direction').val();
map.setZoom(7);
var currentLatLng = new google.maps.LatLng(lat, lng);
map.setCenter(currentLatLng);
var directionsRenderer = new google.maps.DirectionsRenderer();
directionsRenderer.setMap(map);
directionsRenderer.setPanel(document.getElementById('direction'));
var directionsService = new google.maps.DirectionsService();
/////////////////////
default_unit_system = google.maps.UnitSystem.METRIC;
if (current_unit == "km") {
default_unit_system = google.maps.UnitSystem.METRIC;
} else if (current_unit == "miles") {
default_unit_system = google.maps.UnitSystem.IMPERIAL;
}
/////////////////////
var request = {
origin: ori,
destination: lat+','+lng,
travelMode: google.maps.DirectionsTravelMode.DRIVING,
unitSystem: default_unit_system
};
directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsRenderer.setDirections(response);
} else {
//alert('Error: ' + status);
$('#direction').append('<table width="100%"><tr><td>Direction not found. Please try again.</td></tr></table>');
}
});
$('#direction-form').nextAll().remove();
return false;
});
}
I agree with Dr.Molle .
Still, One thing that can be useful for many overlays (like markers, like infowindows, ...): Store the objects in an array;
if needed, keep that array on the global scope;
then you can easily remove them from the map.
var renderObjects = [];
function clearRenderObjects() {
for(var i in renderObjects) {
renderObjects[i].setMap(null);
}
}
$('#direction-form').submit(function () {
// clear previous
clearRenderObjects();
...
var directionsRenderer = new google.maps.DirectionsRenderer();
directionsRenderer.setMap(map);
// add to the array
renderObjects.push(directionsRenderer);
...
});
Use the same DirectionsRenderer-instance for all requests(currently you create a new instance on each request)

TypeError in JavaScript, Google Maps API

I'm currently developing a Webapps using the Google Maps API. I want to plot X different routes simultaneosly to the same destination location.
If I plot one, it works, but when I work with arrays (Because I don't know how many routes I will plot finally) it shows me this type of errors. The code when calculating the routes is like these.
var rendererOptions = [];
var directionsDisplay = [];
for (var k = 0; k < carLatLng.length; k++) {
rendererOptions[k] = {
map: map
};
directionsDisplay[k] = new google.maps.DirectionsRenderer(rendererOptions[k]);
var request = {
origin: carLatLng[k],
destination: place.geometry.location,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService = new google.maps.DirectionsService();
directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay[k].setDirections(response);
} else alert('Failed to get directions');
});
}
The error tells me TypeError: directionsDisplay[k] is undefined. (It refers to the one inside the if() clause)
Hope guys you could help me. I have tried some options but none of them works. Only works when I eliminate the for loop (and the array-type)
Thank you
directionsService.route is asynchronous - by the time the last repsonse is received, the loop would've run it's course, and k == carLatLng.length - thus directionsDisplay[k] will be undefined
What you need is to change
directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay[k].setDirections(response);
} else alert('Failed to get directions');
});
to something like
function(directionsDisplay) {
directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
} else alert('Failed to get directions');
});
}(directionsDisplay[k]);
there's probably easier ways to make a closure, but my mind is addled at the moment
edit: for some clarity, maybe, hopefully -
function(captured_k) {
directionsService.route(request, function (response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay[captured_k].setDirections(response);
} else alert('Failed to get directions');
});
}(k);

how to turn a function into angular scope function

i've a code like below for calculate distance between two points, this is a code for my ionic project. i used Angularjs-google-maps by allenhwkim, and i want to turn the code into angular scope function so it can run on my View. by the way i get this code from my last question in this forum.
for calculate the distance :
var calcRoute = function(origin,destination,cb) {
var dist;
var directionsDisplay;
var directionsService = new google.maps.DirectionsService();
directionsDisplay = new google.maps.DirectionsRenderer();
var request = {
origin:origin,
destination:destination,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
cb(null, response.routes[0].legs[0].distance.value / 1000);
}
else {
cb('pass error information');
}
});
};
code below for running the function and hold the result in $scope.A so i can call the result by typing {{A}} on my View
calcRoute("-7.048443, 110.441022","-7.048264, 110.440388", function (err, dist) {
if (!err) {
$scope.A = dist;
}
});
the problem is, i just can use the function inside my controller and send the result with $scope, but how to turn the code for example to {{ calc(ori,dest) }} and return the distance in my View.
i've tried to do like this :
$scope.calc = function(ori,dest){
var calcRoute = function(origin,destination,cb) {
var dist;
var directionsDisplay;
var directionsService = new google.maps.DirectionsService();
directionsDisplay = new google.maps.DirectionsRenderer();
var request = {
origin:origin,
destination:destination,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
cb(null, response.routes[0].legs[0].distance.value / 1000);
}
else {
cb('pass error information');
}
});
};
calcRoute(ori,dest, function (err, dist) {
if (!err) {
return dist;
}else{
console.log("failed");
}
});
return calcRoute();
};
and call the function inside my View like this :
{{calc("-7.048443, 110.441022","-7.048264, 110.440388")}}
it's not working,
return undefined and show console error below :
Error: [$interpolate:interr] Can't interpolate:
{{calc("-7.048443, 110.441022","-7.048264, 110.440388")}}
InvalidValueError: in property origin: not a string; and not a LatLng or LatLngLiteral: not an Object
hope anyone can help me,thanks :))
Not sure you can compute the function on the fly and print the return value.
What you can do is:
Bind your function to a scope function $scope.calc = function(x,y){...}
inside do the usual assignment $scope.A = dist .
In the view just print {{A}}.
To call the function simply use calc(ori,dest). (from your code I didn't get where you should call it).
The error you mentioned is that you are calling calcRoute twice, once with parameters, and once without:
calcRoute(ori,dest, function (err, dist) {
if (!err) {
return dist;
}else{
console.log("failed");
}
});
return calcRoute();
The bigger problem is that you are not going to be able to evaulate your distance this way. Check out this SO post on evaluating asynchronous expressions.
Infinite loop with Angular expression binding
You're going to have to bind your values to $scope. If you're worried about cluttering up your controller with tons of $scope variables you could make an array and add multiple values to it, then use an ng-repeat to display the information in the view.

How to wait for Direction Service to complete to access Direction property of Direction Display

I'm doing my work with Google Map API. To draw a route between two points, I use this function:
function calcRoute(start, end) {
var pStart = new google.maps.LatLng(start.lat(), start.lng());
var pEnd = new google.maps.LatLng(end.lat(), end.lng());
var request = {
origin: pStart,
destination: pEnd,
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(result);
// Box the overview path of the first route
var path = result.routes[0].overview_path;
boxes = rboxer.box(path, distance);
//drawBoxes(boxes);
nearbyMarkets = search_market(boxes);
// PUT HERE???
}
});
}
After this, I need access the Direction Display object, which only available after the route is rendered successfully (means this function's done). I tried to put that code block in that position, but at that time, the Direction property of Direction Display is still not available, so it's failed. But if I call it after calcRoute function, it's OK.
So, my question is, how can I know when the callback finish so that I can continue my work? I've tried putting a flag like below, but it was unsuccessful, the loop is infinite.
function calcRoute(start, end) {
var pStart = new google.maps.LatLng(start.lat(), start.lng());
var pEnd = new google.maps.LatLng(end.lat(), end.lng());
var pass = false;
var request = {
origin: pStart,
destination: pEnd,
travelMode: google.maps.TravelMode.DRIVING
};
directionsService.route(request, function(result, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(result);
// Box the overview path of the first route
var path = result.routes[0].overview_path;
boxes = rboxer.box(path, distance);
//drawBoxes(boxes);
nearbyMarkets = search_market(boxes);
pass = true;
}
});
while (!pass) {
}
}
Observe the directions_changed-event:
google.maps.event.addListener(directionsDisplay, 'directions_changed',function(){
if(this.get('directions')){
//directions are available, do something
}
});

Categories