1

为了在 Google 地图中为标记创建信息窗口,我使用了一个数组在我的 for 循环中创建“一次性对象”。但是,我的方法似乎不起作用。单击标记没有任何作用,当我检查控制台时,我收到以下错误消息:

Uncaught TypeError: Cannot call method 'open' of undefined 

当我不将对象分配给数组索引时,单击任何创建的标记只会打开最后一个信息窗口(这意味着当对象被覆盖时,它会更新对先前对象的所有引用)。

我该如何规避这个?

markers = []
infowindows = []
counter = 0
for location in exports.response.locations
    myLatlng = new google.maps.LatLng(location.latitude, location.longitude);
    markers[counter] = new google.maps.Marker(
        position: myLatlng
        map: map
        title: location.name
    )
    contentString = '<div id="info_content_' + location.id + '">' + '<h3>' + location.name + '</h3>' + '<ul>' + '<li>' + location.address + ', ' + location.city + '</li>' + '</ul>'
    infowindows[counter] = new google.maps.InfoWindow(content: contentString)

    google.maps.event.addListener markers[counter], "click", ->
        infowindows[counter].open(map, markers[counter])

    counter++

笔记

问题区域是上面代码中的倒数第三行。( infowindows[counter].open(map, markers[counter]))

回答

几乎每个对这个问题的回复都帮助我找到了解决方法,但是 - 为了记录(以及稍后准备这个问题的任何人),我用 foreach 解决了它:

markers = []
infowindows = []
exports.response.locations.forEach (location) ->
    myLatlng = new google.maps.LatLng(location.latitude, location.longitude);
    markers[location.id] = new google.maps.Marker(
        position: myLatlng
        map: map
        title: location.name
    )
    contentString = '<div id="info_content_' + location.id + '">' + '<h3>' + location.name + '</h3>' + '<ul>' + '<li>' + location.address + ', ' + location.city + '</li>' + '</ul>'
    infowindows[location.id] = new google.maps.InfoWindow(content: contentString)

    google.maps.event.addListener markers[location.id], "click", ->
        infowindows[location.id].open(map, markers[location.id])
4

2 回答 2

2

我认为您的问题是counter将不再有有效的索引:

for location in exports.response.locations

    google.maps.event.addListener markers[counter], "click", ->
        infowindows[counter].open(map, markers[counter])

    counter++

counter在 onClick 处理程序闭包中捕获。

在 onClick 处理程序运行之前,它将超出界限。

所有这些处理程序最终将使用相同的counter.

于 2013-10-08T03:59:18.797 回答
1

addListener 异步触发代码。因此,调用监听器的回调函数时的计数器值与声明函数时的值是不一样的。要将变量冻结为声明函数时的值,您必须将它们放在闭包中。下面的完整证明选项。在循环中声明 currentCounter 就足够了,但它可能有助于明确使用闭包。

markers = []
infowindows = []
counter = 0
for location in exports.response.locations
    myLatlng = new google.maps.LatLng(location.latitude, location.longitude);
    markers[counter] = new google.maps.Marker(
        position: myLatlng
        map: map
        title: location.name
    )
    contentString = '<div id="info_content_' + location.id + '">' + '<h3>' + location.name + '</h3>' + '<ul>' + '<li>' + location.address + ', ' + location.city + '</li>' + '</ul>'

    infowindows[counter] = new google.maps.InfoWindow(content: contentString)
    google.maps.event.addListener markers[counter], "click", (function(infowindows, markers, currentcounter) { 
        return function() {  infowindows[currentCounter].open(map, markers[currentCounter]) }
    })(infowindows, markers, counter)
    counter++    

请参阅循环内的 JavaScript 闭包 - 简单实用示例以获取更多实用示例

于 2013-10-08T04:23:05.273 回答