Stephen Adkins
Stephen Adkins

Reputation: 65

Function not defined in javascript object

I'm trying to invoke a method using callbacks and object orientated javascript dealing with google api, but I keep getting an undefined error with the function being called.

js:

var generateMap = (function(){
var map;
return{
    offsetCenter: function(lat, lng){
        lat = lat;
        lng = lng + .01;

        return new google.maps.LatLng(lat, lng);
    }

    ,initialize: function(location){
        console.log("test");
        var latLng = new google.maps.LatLng(location.coords.latitude, location.coords.longitude);

        var mapOptions = {
            zoom: 15,
            center: latLng,
            mapTypeId: google.maps.MapTypeId.ROADMAP,
            disableDefaultUI: true,
            draggable: false,
            scaleControl: false,
            scrollwheel: false
        };

        map = new google.maps.Map(document.getElementById('map'), mapOptions);
        var newCenter = offsetCenter(location.coords.latitude, location.coords.longitude);
        map.setCenter(newCenter);

        var marker = new google.maps.Marker({
            position: new google.maps.LatLng(location.coords.latitude, location.coords.longitude),
            title: 'Point A',
            map: map,
            draggable: false
        });
    }

    ,createMap: function(){
        navigator.geolocation.getCurrentPosition(initialize);
    }
};
})();
$(document).ready(function(){
    var callbacks = $.Callbacks();
    callbacks.add(
        generateMap.createMap
    );
    callbacks.fire();
})

Error: ReferenceError: initialize is not defined

Any reason why this could be happening?

Upvotes: 0

Views: 1061

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1075895

The main problem is that createMap refers to a symbol that isn't defined:

,createMap: function(){
    navigator.geolocation.getCurrentPosition(initialize);
    // Here ---------------------------------^
}

Unlike Java or C#, JavaScript has no implied this for methods on the current instance. You have to specify it.

Now, because generateMap is a singleton, and initialize doesn't use this anywhere, you can correct it like this:

,createMap: function(){
    navigator.geolocation.getCurrentPosition(generateMap.initialize);
}

Again, that only works because generateMap is a singleton, and initialize doesn't use this.


In the general case (if it weren't a singleton, or initialize used this), you'd manage this:

This code:

callbacks.add(
    generateMap.createMap
);

...will add a reference to the createMap function to the callbacks list, but that function isn't in any way bound to the generateMap object. So when it's called, this won't refer to generateMap (other than closing over it, but again, we're assuming here we aren't dealing with a singleton). You can fix that with ES5's Function#bind or jQuery's $.proxy:

callbacks.add(
    generateMap.createMap.bind(generateMap)
);
// or
callbacks.add(
    $.proxy(generateMap.createMap, generateMap)
);

Each of those creates a function that, when called, will turn around and call createMap making this = generateMap during the call.

Then in createMap, we fix the initialize thing in a similar way:

,createMap: function(){
    navigator.geolocation.getCurrentPosition(this.initialize.bind(this));
}
// or
,createMap: function(){
    navigator.geolocation.getCurrentPosition($.proxy(this.initialize, this));
}

More about this in JavaScript on my blog:

Upvotes: 1

Related Questions