Javascript variable undefined outside of class - javascript

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

Related

How to correctly pass "this" into function?

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

How to make local varible global javascript

I have this class like so :
https://jsfiddle.net/0sh7fLtp/
When I create a new object of this class, my local variable can't be seen even when I assign to window in the class:
function Hilitor() {
var excat;
this.setMatchType = function(type) {
if (type == "exact"){
window.excat = true;
}
};
this.setRegex = function(input) {
alert(excat);
};
this.apply = function(input) {
this.setRegex();
};
}
and this is how i call it :
var myHilitor = new Hilitor();
myHilitor.apply();
myHilitor.setMatchType("exact");
Not sure I completely understand your question but you are trying to compare a variable "excat" to string "excat"... See this fiddle to how you can make your var a string and then get desired output..
https://jsfiddle.net/shemdani/0sh7fLtp/5/
var myHilitor = new Hilitor();
myHilitor.setMatchType("excat");
myHilitor.apply();
function Hilitor()
{
var excat;
this.setMatchType = function(type)
{
if(type == "excat"){window.excat = true;}
};
this.setRegex = function(input)
{
alert(window.excat);
};
this.apply = function(input)
{
this.setRegex();
};
}
Two main problems
1) Your var exact inside the function is not a global variable and so not accessible on the window object. (But that's a good thing).
Your code will work if you remove window.exact for just exact
this.setMatchType = function(type)
{
if(type == "exact"){excat = true;}
};
2) You are also calling apply before you call setMatchType. Switching them like this works:
var myHilitor = new Hilitor();
myHilitor.setMatchType("excat");
myHilitor.apply();
Working example

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

Cannot iterate over the object in javascript

Struggling to iterate over the object in javascript. I can usually do the obvious key iteration and even tried some functions I have found for that purpose itself. Although, when I print the object to the console it works. I am struggling to access its properties. Puzzled. Lost quite some time with this so turning to stackoverflow for some help.
Assume I have a sitemap.xml stored somewhere locally.
<script>
(function() {
tree = new TreeModel();
root = tree.parse({ name: "domain.com" });
var rootNode = root.first(function (node) {
return node.model.name === "domain.com";
});
function idEq(name) {
return function (node) {
return node.model.name === name;
};
}
var rootDomainHttp = "http://www.domain.com";
var rootDomainHttps = "https://www.domain.com";
var xmlhttp;
if(window.XMLHttpRequest) xmlhttp = new XMLHttpRequest();else xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.onreadystatechange = function() {
if(xmlhttp.readyState==4 && xmlhttp.status==200) {
loc = xmlhttp.responseXML.documentElement.getElementsByTagName("loc");
for(i=0;i<loc.length;i++) {
var fullURL = loc[i].firstChild.nodeValue;
//console.log(fullURL);
if(fullURL == rootDomainHttp || fullURL == rootDomainHttps)
{
document.getElementById("urls").appendChild(document.createTextNode( loc[i].firstChild.nodeValue ));
document.getElementById("urls").appendChild(document.createElement("br"));
}
else
{
fullURL = fullURL.replace(rootDomainHttps, '');
fullURL = fullURL.replace(rootDomainHttp, '');
var urlComponents = fullURL.split ('/').filter(function(el) {return el.length != 0});;
//console.log(urlComponents);
var arrayLength = urlComponents.length;
var currentNode;
var parentNode = root.first(idEq("domain.com"));
//console.log(fullURL);
for (var component in urlComponents) {
if (urlComponents.hasOwnProperty(component)) {
//console.log("started loop for URL components: " + urlComponents[component]);
var currentNode = root.first(idEq(urlComponents[component]));
if (currentNode == undefined)
{
parentNode.addChild(tree.parse({name: urlComponents[component]}));
parentNode = root.first(idEq(urlComponents[component]));
}
else
{
var currentNode = root.first(idEq(urlComponents[component]));
var componentLevel = component;
var nodesThatMatchPredicate = root.all(function (node) {
return node.model.name == urlComponents[component];
});
var nodeLevel = 0;
for(var node in nodesThatMatchPredicate)
{
if(nodeLevel != component)
{
parentNode.addChild(tree.parse({name: urlComponents[component]}));
}
else
{
//console.log("already exists...");
}
}
var parentNode = root.first(idEq(urlComponents[component]));
}
}
}
document.getElementById("urls").appendChild(document.createTextNode( loc[i].firstChild.nodeValue ));
document.getElementById("urls").appendChild(document.createElement("br"));
}
}
}
}
xmlhttp.open("GET", "sitemap_001.xml", true);
xmlhttp.send(null);
console.log(JSON.stringify(root));
console.log(JSON.stringify(root.model));
//console.log(root);
/*var url = 'data:text/json;charset=utf8,' + encodeURIComponent("something");
window.open(url, '_blank');
window.focus();*/
})();
</script>
I am using a <script type="text/javascript" src="http://jnuno.com/tree-model-js/vendor/jnuno/TreeModel.js"></script> library.
On the console, when I do console.log(root); I get:
Node {config: Object, model: Object, children: Array[0], isRoot: function, hasChildren: function…}children: Array[2]config: Objectmodel: Objectchildren: Array[2]0: Objectchildren: Array[1]name: "healthcarezone"proto: Object1: Objectchildren: Array[1]name: "protection"proto: Objectlength: 2__proto__: Array[0]name: "domain.com"proto: Object__proto__: Node
But when accessing it directly. It gives me undefined. Any help and examples much appreciated.
Occasionally javascript does not execute in the order that you would expect. This article may help you.
I think that a line of code is taking too long to return the value of a variable that a latter line is dependent on. As a result you can get null and undefined values when running calculations off of variables that are non existent. You probably should be using callback functions to ensure that your variables are returned before you try to use said variables.

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

Categories