Javascript class's variables undefined, while they are (to me)

Hi,

I am having a few problems with a javascript class that I need (want) for an application.

The code here is version 4 or 5 or something. I have tried creating a class with prototypes, with the dynamic prototype method, using the constructor, etc. But none of them worked properly.

The problem I am having is as follows:

I set the var this.divId of the object to a value, in this case ‘guide_map’. This is the id of the div that the google maps api will use to put the map into. But in the function ‘renderMap’ when I call this.divId it says it is undefined. But when I alert mymap.divId it shows up like it should.

When I do console.log(this) it shows Window 1, which would mean, I think, JS is not (yet) my language, that ‘this’ does not refer to the object, but to the whole window.

How do I fix this?

The code:


function renderMap(){
	var options = {zoom: this.defaultZoom, center: this.divId, mapTypeId: google.maps.MapTypeId.ROADMAP};
	this.map = new google.maps.Map(document.getElementById(this.divId), options);		
}

function setDefaultLatLng(value, isaddress){
	if (isaddress == null){
		isaddress = false;
	}
	if(isaddress){
	   address = value;
	   this.geocoder.geocode({address:address}, this.handleSetDefaultLatLngAddress);
	}
	else{
	//Value = object: {lat:12.12, lng: 12.12}
	this.defaultLatLng = new google.maps.LatLng(value.lat, value.lng);
	}
}

function setDefaultZoom(iZoom){
	this.defaultZoom = iZoom;
}

function handleSetDefaultLatLngAddress(results, status){
	if(status == google.maps.GeocoderStatus.OK){
		//this.map.panTo(results[0].geometry.location);
		//this.defaultLatLng = new google.maps.LatLng(results[0].geometry.location.a, results[0].geometry.location.b);
		this.defaultLatLng = new google.maps.LatLng(results[0].geometry.location.a, results[0].geometry.location.b);
		this.renderMap();
	}		
}

function setDivId(containerId){
	this.divId = containerId;
}

function dcMap(){
    //this.defaultLatLng;
    this.defaultZoom = 12;
    //The geocoder
    this.geocoder = new google.maps.Geocoder();
    //Attach the functions
	this.setDivId = setDivId;
	this.renderMap = renderMap;
	this.setDefaultZoom = setDefaultZoom;
	this.setDefaultLatLng = setDefaultLatLng;
	this.handleSetDefaultLatLngAddress = handleSetDefaultLatLngAddress;
};

var mymap = new dcMap();
mymap.setDivId('guide_map');
mymap.setDefaultZoom(13);
mymap.setDefaultLatLng('Amsterdam, Netherlands', true);


Hi, I’m by no means a JS person.

However you might want to check into the scopes of the variables. Make sure that the scope isn’t local, but rather global.
You set a variable in a function so (this isn’t coming from a pro, so excuse me if I’m wrong) the scope of the variable only lasts as long as the function calling it/the function itself.

Just an idea :). Hope it helps.

The problem is here.


    if(isaddress){
       address = value;
       this.geocoder.geocode({address:address}, this.handleSetDefaultLatLngAddress);
    }

The geocode method doesn’t know that it should use an implied object when calling the handleSetDefaultLatLngAddress method, so by default, the window object is used. You can do a trick with a closure.


    if(isaddress){
       address = value;
       var impliedObject = this;
       this.geocoder.geocode({address:address}, function(results, status){
           return impliedObject.handleSetDefaultLatLngAddress(results, status);
       });
    }

A more general approach, so you don’t need to know what arguments the function needs to accept, would be


function proxy(impliedObject, func) {
    return function(){
        func.apply(impliedObject, arguments);
    }
}

Then you could do


    if(isaddress){
       address = value;
       this.geocoder.geocode({address:address}, proxy(this, this.handleSetDefaultLatLngAddress));
    }

I would expect most people not familiar with javascript to be pretty lost reading that :confused:

Thanks for the replies guys.

RyanReese - True there is a problem with the scope. I tried declaring it beforehand, in a function called setThisandThat(value), etc etc. They all failed.

crmalibu -
Thanks I will give this a try, it looks very promising. I quickly read up on the ‘apply’ method, to me it looks very pro ;).

I will keep you posted here on what happens. I am hopeful.

-EDIT-

Thanks! Works like a charm, this now finally refers to the actual object again and not to the window! Wouldn’t have gotten this on my own. Time to rewrite my class to a better style again.

Thank you :).

I think this article does a good job of explaining scope binding issues:

In case you don’t fully see why this was pointing to window before implementing crmalibu suggestions.

Thanks, I will read the article. You can never know too much.