views:

144

answers:

3

I have the following (simplified) object literal. The icons method uses closure to hide the icons variable, which I'd like to have as an associative array for later lookups.

var MapListings = {
    icons: function () {
        var allIcons = [] ;

        return {
            add: function (iconType, iconImage) {
                var icon = new GIcon(MapListings.baseIcon);
                icon.image = iconImage;
                allIcons[iconType] = icon; // fails, but this is what I want
                // allIcons.push(icon); // works, but this is not what I want
            },
            get: function () {
                return allIcons;
            }
        };

    } ()
}

I add items to the to the icons object like so:

MapListings.icons.add("c7", "/images/maps/blue.png");
MapListings.icons.add("c8", "/images/maps/red.png");

The following doesn't work:

allIcons[iconType] = icon;

But this does:

allIcons.push(icon);

Outside of the closure the associative array style works fine, so perhaps there is a conflict with jQuery? The error I get in firebug a is undefined looks to come from the library. I'd like to maintain the associative array style.

Any ideas?

Update

It looks like this conflict is coming from google maps. Odd, not sure of a way around this.

Dumbass Update

The part of my object literal that returned a base GIcon() object wasn't returning an object at all. So, the object didn't have the right properties.

baseIcon: function () {
    var base = new GIcon();
    base.shadow = '/images/maps/shadow.png';
    base.iconSize = new GSize(12, 20);
    base.shadowSize = new GSize(22, 20);
    base.iconAnchor = new GPoint(6, 20);
    base.infoWindowAnchor = new GPoint(5, 1);
    return base;
}

And MapListings.baseIcon is NOT the same as MapListings.baseIcon()! D'oh

+4  A: 

if you want a lookup table, just do var allIcons = {}

EDIT: Though technically it should work either way, as an array IS an object. Are you sure there isn't more to this?

EDIT #2: Can't you just make allIcons as a property of MapListings?

EDIT #3: I think it's working, but maybe you're not accessing it right? That or it fails creating the object with Google somehow, or the error you posted is happening elsewhere, and not here

function GIcon(){};
var MapListings = {
    icons: function () {
        var allIcons = [] ;

        return {
            add: function (iconType, iconImage) {
                var icon = new GIcon(MapListings.baseIcon);
                icon.image = iconImage;
                allIcons[iconType] = icon; // fails, but this is what I want
                // allIcons.push(icon); // works, but this is not what I want
                window.x = allIcons
            },
            get: function () {
                return allIcons;
            }
        };

    } ()
};

MapListings.icons.add("c7", "/images/maps/blue.png");
MapListings.icons.add("c8", "/images/maps/red.png");

alert( MapListings.icons.get()['c8']['image'] )

You shouldn't loop using .length but instead directly access c7 or c8.

x = MapListings.icons.get();
for ( var prop in x ) {
    if ( x.hasOwnProperty(prop ) ) {
        alert( x[prop]['image'] )
    }
}
meder
tried that already, same error: a is undefined
ScottE
+1 for noting that the fault is elsewhere.
Anurag
@meder - this defeats the purpose of the closure. I'd prefer to leave it as a private member as the .add method does some other work. I only want icons added this way.
ScottE
See my edit above. The lesson of the day is to debug. Sorry for the bother.
ScottE
A: 

allIcons[iconType] = icon; fails because allIcons is an Array, not an object. Try initializing allIcons to {} instead. That would allow you to place items in the collection by key.

Jacob
Not true, it works just fine outside of my example. They aren't recommended to be used in this fashion, but look here: http://www.hunlock.com/blogs/Mastering_Javascript_Arrays
ScottE
Nothing that I can find in that document says that string indexes are allowed for Arrays.
Jacob
@Jacob: Any object in JS can have properties, so an array can too.
casablanca
Ah, I what you might mean. I guess you can add arbitrary properties to an Array object. But it's not the same as an associative array.
Jacob
Yes, correct. It's a bit of a fake.
ScottE
+1  A: 

So one thing you could do to fix this is change the way you reference the array. Since external to your add method you do this:

MapListings.icons["c7"]

You can also just use this to add to your array inside your add function:

add: function (iconType, iconImage) { 
    MapListings.icons[iconType] = iconImage;
}, 
spinon