tags:

views:

86

answers:

2

Hey,

This is my first foray into OO JS, having issues.

Ideally in this scenario, I'd have a mapLocation object, which i could just pass in coordinates, icon, the HTML to display upon click and that's it. I'd add it to my Google map on the page and I'd have something somewhat re-usable. Obviously this would be refactored later.

Also, I'm not specifically happy about how my code looks at the moment. :)

Here's the object that I'm coming up with.

function mapLocation() {

 this.lat = 0;
 this.lng = 0;
 this.icon = '';
 this.html = '';
 this.getLocation = getLocation;
}

function getLocation() {
 var baseIcon = new GIcon(G_DEFAULT_ICON);
    baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png";
    baseIcon.iconSize = new GSize(20, 34);
    baseIcon.shadowSize = new GSize(37, 34);
    baseIcon.iconAnchor = new GPoint(9, 34);
    baseIcon.infoWindowAnchor = new GPoint(9, 2);
 var letteredIcon = new GIcon(baseIcon);
 letteredIcon.image = this.icon;
 var point = new GLatLng(this.lat, this.lng);
 var marker = new GMarker(point, { icon:letteredIcon });

 function show() {
  marker.openInfoWindowHtml('Lat: '+this.lat+'<br />Lng: '+this.lng+'<br /><img src="'+this.icon+'" />');
 }
 alert(this.lat);
 GEvent.addListener(marker, "click", show);
 return marker;
}

And here's my implementation.

var a = new mapLocation;
a.lat = 52.136369;
a.lng = -106.696299;
a.icon = 'http://www.google.com/mapfiles/markerA.png';
a.html = 'asdf fdsa';

var b = a.getLocation();
map.addOverlay(b);

So I get window showing up, my marker, but show() function pop up with undefined in it.

I'm curious what I'm doing wrong - how I'm thinking wrong - in this problem.

Thanks for the look.

A: 
    var _this = this;
    function show() {
            marker.openInfoWindowHtml('Lat: '+_this.lat+'<br />Lng: '+_this.lng+'<br /><img src="'+_this.icon+'" />');
    }

Remember that unless a function is called as a member of an object, this === window.

Also, a cleaner way to express all of this is:

function mapLocation() {
   // constructor stuff
}

mapLocation.prototype = {
  getLocation: function() {
    // code for getLocation 
  }
};

Then you don't have to assign this.getLocation in the constructor.

noah
fwiw prototype is better than naked method assignment because it will only create one instance of the method object vs one (potentially different) instance per instance of the class object
annakata
A: 

Can't be sure without those extra functions in there but I imagine it's a 'this' reference problem because your show function isn't creating a closure.

Try this (Edit: I'm an idiot, forgot 'this' issues):

function show() {
  var x = this;
  return function(){marker.openInfoWindowHtml('Lat: '+x.lat+'<br />Lng: '+x.lng+'<br /><img src="'+x.icon+'" />');}
}

GEvent.addListener(marker, "click", show());

As for OOJS... comments to explain:

//convention is to name JS classes with an uppercase character
function MapLocation(params) 
{
    //instantiate from a params object to keep a flexible contructor signature
    //(similarly you can use the native arguments object but I prefer to be explicit)
    this.lat = (params.lat ? params.lat : 0);
    this.lng = (params.lng ? params.lng : 0);
    this.icon = (params.icon ? params.icon : '');
    this.html = (params.html ? params.html : '');

    //keep methods contained within the class definition
    if (typeof(this.geolocation) == 'undefined') //execute once
    {
     //by binding methods with prototype you only construct a single instance of the function
     MapLocation.prototype.getLocation = function ()
              {
               /* ... */
              }
    }
}

//property set at constructor
var a = new MapLocation({lat:52.136369, lng:-106.696299, icon: 'http://www.google.com/mapfiles/markerA.png'});

//deferred property setting
a.html = 'asdf fdsa';
annakata
Your formatting is off... can't see the body of getLocation.Making show return a function isn't going to change the value of this. You need to either change this to a reference to the object, or call show as a method of the object.
noah
You'll notice I'd corrected the second problem, but the body of getLocation was deliberately cropped for brevity, hence the /* ... */.
annakata
this will still be the window object. You need to save a reference to this inside the constructor function.
noah