How to correctly pass "this" into function? - javascript

I struggle passing this into my function as demonstrated below:
console.log('geolocation is ' + this.isGeolocating);
let geocoder = new google.maps.Geocoder;
geocoder.geocode({'location': geolocation}, function(results, status, self = this) {
console.log('geolocation is ' + self.isGeolocating);
if (status === 'OK') {
if (results[0]) {
console.log(results[0]);
self.geolocated = 'success';
} else {
// No results found
self.geolocated = 'error';
}
} else {
console.log('Geocoder failed due to: ' + status);
self.geolocated = 'error';
}
});
this.isGeolocating = false;
this is properly accessible before and after the function, but how can I pass it through? self in my case is undefined as well.

There's typically three approaches. One is to assign this to another variable, conventionally named self or that, before the function; the variable will be captured into the function's closure.
let that = this;
geocoder.geocode(..., function(...) {
that.isGeolocating
});
Another is to explicitly tell the function what this should be, using bind:
geocoder.geocode(..., function(...) {
this.isGeolocating
}.bind(this));
The third one is to use a rocket function, which does not reassign this:
geocoder.geocode(..., (...) => {
this.isGeolocating
});

Try this:
let myBeautifulThis = this;
let geocoder = new google.maps.Geocoder;
geocoder.geocode({'location': geolocation}, function(results, status) {
console.log('geolocation is ' + myBeautifulThis.isGeolocating);
});

You need to either store a reference to this in a variable outside of your function, or use arrow functions.
So either
let self = this;
geocoder.geocode({'location': geolocation}, function(results, status) {
// you existing code here
// use self.isGeolocating
});
of just
geocoder.geocode({'location': geolocation}, (results, status) => {
// using this in here will use the this of the outer scope.
// use this.isGeolocating
});

Related

I cant use variable out of function [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I declared a variable names with an empty array value out of the function, then used it inside the function to assign returned value, then I want to use it outside this function, but outside the function this variable remains empty.
Please explain what I'm doing wrong.
handleUpdateInputBusinessName = (searchText) => {
var names = [];
var displaySuggestions = function(predictions, status) {
if (status !== google.maps.places.PlacesServiceStatus.OK) {
alert(status);
return;
}
predictions.forEach(function(prediction) {
let name = prediction.description;
names.push(name);
});
console.log('names_in:', names); // valid predictions from Google Maps Service
return names;
};
console.log('names_out:', names); // []
var service = new google.maps.places.AutocompleteService();
service.getQueryPredictions({ input: searchText, types: '(cities)'
}, displaySuggestions);
Here's the boiled down version:
a = [];
var b = () => {
a.push(1);
console.log('inside:', a)
};
console.log('outside:', a);
b();
The "outside" console log is running before the displaySuggestions function is called, so the data is not yet populated in the array.
you have to use js anonymous function syntax to increse the scope of names array below is the code.
handleUpdateInputBusinessName = (searchText) => {
var names = [];
var displaySuggestions = (predictions, status) => {
if (status !== google.maps.places.PlacesServiceStatus.OK) {
alert(status);
return;
}
predictions.forEach((prediction) => {
let name = prediction.description;
names.push(name);
});
console.log('names_in:', names); // valid predictions from Google Maps Service
return names;
};
console.log('names_out:', names); // []
var service = new google.maps.places.AutocompleteService();
service.getQueryPredictions({ input: searchText, types: '(cities)'
}, displaySuggestions);
hope this heps.

Cannot access variable in Javascript array. Console.log says undefined

I have an object which contains an array that I then pass to another function in order for that function to use. The only thing is, when I go to access these variables, console.log says they are undefined. It's strange as when I log the whole array it ways the values are there but when I go to access the array element specifically, it returns undefined.
Here is my code:
googleMapsFunctions.prototype.calculateDistances = function() {
var that = this;
console.log(that.latLngArray);
var closeClubs = [];
var sortable = [];
var resultsArray = [];
jQuery(this.clubs).each(function(key, club) {
var clubLatLng = new google.maps.LatLng(club.latitude, club.longitude);
var distanceFromLoc = clubLatLng.distanceFrom(that, "", "");
//alert(distanceFromLoc);
//that.clubs[key].distance = distanceFromLoc;
//closeClubs.push(club);
});
closeClubs.sort(function(a, b) {
return a.distance - b.distance;
});
}
googleMapsFunctions.prototype.setLatLng = function() {
var that = this;
this.geocoder.geocode({'address' : this.location}, function(results, status) {
if(status === "OK") {
that.latLngArray.push(parseFloat(results[0].geometry.location.lat()));
that.latLngArray.push(parseFloat(results[0].geometry.location.lng()));
}
});
}
//Client Code
var googleMapsClass = new googleMapsFunctions(JSONItems, searchTerm);
googleMapsClass.setLatLng();
googleMapsClass.calculateDistances();
I am using console.log to print out the array (that.latLngArray) which gives the following:
I then click on the aray brackets and it takes me to the following (which is the correct information).
I just can't seem to access these variables and it says that they are undefined.
Can anyone see what is happening here?
Thanks
Simplest thing to do would be to just move the distance calculation inside the callback:
googleMapsFunctions.prototype.setLatLng = function() {
var that = this;
this.geocoder.geocode({'address' : this.location}, function(results, status) {
if(status === "OK") {
that.latLngArray.push(parseFloat(results[0].geometry.location.lat()));
that.latLngArray.push(parseFloat(results[0].geometry.location.lng()));
// now it's safe to check the distances
that.calculateDistances();
}
});
}

Javascript variable undefined outside of class

I am relatively new to Javascript OOP and have been attempting to build a class to handle some functionality within my application.
The issue I am having is that after I have initialized my class, which sets some values in the constructor, when I call a function of that class which should update some variables within that instance and return them, these variables are coming through as undefined outside of the instance.
Here is my code:
//Google Maps Javascript class
var googleMapsFunctions = function(clubs, location) {
this.clubs = clubs;
this.location = location;
this.latLng = new Array();
this.geocoder = new google.maps.Geocoder();
this.closeClubs = [];
}
googleMapsFunctions.prototype.setLatLng = function() {
this.geocoder.geocode({'address' : this.location}, function(results, status) {
if(status === "OK") {
this.latLng.push(results[0].geometry.location.k);
this.latLng.push(results[0].geometry.location.B);
}
});
}
googleMapsFunctions.prototype.calculateDistances = function() {
var sortable = [];
var resultsArray = new Array();
try {
//alert(this.latLng);
} catch(error) {
alert(error);
}
}
//Client code
var JSONItems = <?php echo $this->JSONItems; ?>;
var searchTerm = "<?php echo $this->searchTerm; ?>";
var googleMapsClass = new googleMapsFunctions(JSONItems, searchTerm);
googleMapsClass.setLatLng();
googleMapsClass.calculateDistances();
When I try and access the 'this.latLng' variable from outside of the instance, it is saying that it is undefined. It is defined and outputting correctly when I log the data from within the 'setLatLng' function though which makes me think this is an encapsulation issue?
Can anybody give me some advice as to why this may be occuring?
Thanks
Keep the reference to the prototypes "this" by setting this to an variable and using it inside the Geocoders callback
var googleMapsFunctions = function(clubs, location) {
this.clubs = clubs;
this.location = location;
this.latLng = new Array();
this.geocoder = new google.maps.Geocoder();
this.closeClubs = [];
}
googleMapsFunctions.prototype.setLatLng = function() {
var that = this;
this.geocoder.geocode({'address' : this.location}, function(results, status) {
if(status === "OK") {
that.latLng.push(results[0].geometry.location.k);
that.latLng.push(results[0].geometry.location.B);
}
});
}

function in Backbone is not defined

I have a view in Backbone which has multiple functions.
The functions I have are initialize, render, answer, answerQuestion, nextQuestion.
Here is the code I have in the initialize function
initialize: function(game) {
_.bindAll(this, 'render', 'answer');
this.render();
}
In the render function I call the answerQuestion function by doing this:
this.answerQuestion();
It works fine.
But in my answer function I call the nextQuestion function the same way and I get this error undefined is not a function, if I just call the function without the this at the start I get this error 'nextQuestion is not defined'
What am I missing to get this working.
Here is the full answer function:
var v = $('.question.current .type').find('.input').val();
if (v !== undefined) {
var t = new Date();
var time_spent = t.getTime() - this.t.getTime();
var self = this;
answer.save().done(function(result, status) {
if (status === 'success') {
this.nextQuestion();
}
});
}
You're referring to the wrong context with: this.nextQuestion();. It should be self.nextQuestion();. Or you could bind the callback to the external function's context like this:
var v = $('.question.current .type').find('.input').val();
if (v !== undefined) {
var t = new Date();
var time_spent = t.getTime() - this.t.getTime();
var self = this;
answer.save().done(function(result, status) {
if (status === 'success') {
this.nextQuestion();
}
}.bind(this));
}

Variable referencing issue with an asynchronous call

I've been playing around with JavaScript and there's something I don't quite understand. I have this piece of code here:
$.getJSON('data.json', function(obj) {
for( var p in obj.List )
{
datas['id'] = obj.List[p].ListingId;
datas['area'] = area;
//console.log(datas);
var geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': datas['area'] }, function(results,status)
{
if(status == google.maps.GeocoderStatus.OK)
{
var latlng = new google.maps.LatLng(results[0].geometry.location.Ya, results[0].geometry.location.Za);
datas['latlng'] = latlng;
//console.log(datas);
}
});
}
});
Ok, now suppose the for loop runs 3 times. If we uncomment the first "console.log(datas)" line and run the page, in the console we see 3 "datas" objects with their own "id" and "area". If I comment that first "console.log(datas)" and uncomment the second "console.log(datas)" in the geocode callback, when I run the code, all 3 "datas" objects are exactly the same in terms of "id", "area", and "latlng". Whereas I expected the 3 "datas" objects would be different with their own latlngs.
Any ideas?
When is the function you pass to the geocoder.geocode function run? If it's not being run immediately then the for loop will run through all three times before the geocode function is run. That means that datas['id'] and datas['area'] will have been set to the last iteration of the loop... in which case you need to capture the datas array inside a closure for the geocode function.
In which case you'd need something like:
$.getJSON('data.json', function(obj) {
for( var p in obj.List )
{
datas['id'] = obj.List[p].ListingId;
datas['area'] = area;
//console.log(datas);
var geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': datas['area'] }, function(datas){ return function(results,status)
{
if(status == google.maps.GeocoderStatus.OK)
{
var latlng = new google.maps.LatLng(results[0].geometry.location.Ya, results[0].geometry.location.Za);
datas['latlng'] = latlng;
//console.log(datas);
}
}}(datas));
}
});
This prevents the datas variable as used by the anonymous function being updated by the for loop.
I think this is a scope problem. By the time that last console.log runs the p variable will already refer to the last obj. You need to capture p in a new scope.
for( var p in obj.List ) {
(function(p) {
datas['id'] = obj.List[p].ListingId;
datas['area'] = area;
geocoder.geocode( { 'address': datas['area'] }, function(results,status) {
...
});
}(p));
}
I think datas has to be declared as a global array? Has it?

Categories