2016-06-21 3 views
-2

私は多くのマーカーでGoogleマップをレンダリングするページを作っています。私は、クリックしたときにインフォ・ウィンドウが各マーカーに表示されるようにします。このため、各マーカーにクリックイベントリスナーを追加する必要がありました。今では何百ものマーカーがあるので、私はforループを使いました。つまり、何百ものマーカーにイベントリスナーを追加する必要があります。私はイベントリスナーを含む行でエラーmarkers[j] isn't definedを取得Google MAP APIでこの関数クロージャが機能しないのはなぜですか?

<!DOCTYPE html> 
<html> 
<head> 
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no"> 
    <meta charset="utf-8"> 
    <title>Info windows</title> 
    <style> 
    html, body { 
     height: 100%; 
     margin: 0; 
     padding: 0; 
    } 
    #map { 
     height: 100%; 
    } 
    #first-tab { 
     position: absolute; 
     top: 10px; 
     left: 10px; 
     width: 100px; 
     height: 100px; 
     background-color: green; 
    } 
    #second-tab { 
     position: absolute; 
     top: 140px; 
     left: 10px; 
     width: 100px; 
     height: 100px; 
     background-color: red; 
    } 
    #third-tab { 
     position: absolute; 
     top: 300px; 
     left: 10px; 
     width: 100px; 
     height: 100px; 
     background-color: yellow; 
    } 

    </style> 
</head> 
<body> 
    <script 
    src="https://code.jquery.com/jquery-2.2.4.js" 
    integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI=" 
    crossorigin="anonymous"></script> 
    <div id="map"></div> 
    <div id="first-tab"></div> 
    <div id="second-tab"></div> 
    <div id="third-tab"></div> 
    <script> 

    function initMap() { 

    var map = new google.maps.Map(document.getElementById('map'), { 
     zoom: 4, 
     center: {lat: -25.363, lng: 131.044} 
    }); 

    var contentString = []; 
    contentString[0] = '<div id="content">'+ 
    '<div id="siteNotice">'+ 
    '</div>'+ 
    '<h1 id="firstHeading" class="firstHeading">Uluru</h1>'+ 
    '<div id="bodyContent">'+ 
    '<p><b>Uluru</b>, also referred to as <b>Ayers Rock</b>, is a large ' + 
    'sandstone rock formation in the southern part of the '+ 
    'Northern Territory, central Australia. It lies 335&#160;km (208&#160;mi) '+ 
    'south west of the nearest large town, Alice Springs; 450&#160;km '+ 
    '(280&#160;mi) by road. Kata Tjuta and Uluru are the two major '+ 
    'features of the Uluru - Kata Tjuta National Park. Uluru is '+ 
    'sacred to the Pitjantjatjara and Yankunytjatjara, the '+ 
    'Aboriginal people of the area. It has many springs, waterholes, '+ 
    'rock caves and ancient paintings. Uluru is listed as a World '+ 
    'Heritage Site.</p>'+ 
    '<p>Attribution: Uluru, <a href="https://en.wikipedia.org/w/index.php?title=Uluru&oldid=297882194">'+ 
    'https://en.wikipedia.org/w/index.php?title=Uluru</a> '+ 
    '(last visited June 22, 2009).</p>'+ 
    '</div>'+ 
    '</div>'; 

    contentString[1] = '<div id="content">'+ 
    '<div id="siteNotice">'+ 
    '</div>'+ 
    '<h1 id="firstHeading" class="firstHeading">New York</h1>'+ 
    '<div id="bodyContent">'+ 
    '<p><b>New York</b>, also referred to as <b>Ayers Rock</b>, is a large ' + 
    'sandstone rock formation in the southern part of the '+ 
    'Northern Territory, central Australia. It lies 335&#160;km (208&#160;mi) '+ 
    'south west of the nearest large town, Alice Springs; 450&#160;km '+ 
    '(280&#160;mi) by road. Kata Tjuta and Uluru are the two major '+ 
    'features of the Uluru - Kata Tjuta National Park. Uluru is '+ 
    'sacred to the Pitjantjatjara and Yankunytjatjara, the '+ 
    'Aboriginal people of the area. It has many springs, waterholes, '+ 
    'rock caves and ancient paintings. Uluru is listed as a World '+ 
    'Heritage Site.</p>'+ 
    '<p>Attribution: Uluru, <a href="https://en.wikipedia.org/w/index.php?title=Uluru&oldid=297882194">'+ 
    'https://en.wikipedia.org/w/index.php?title=Uluru</a> '+ 
    '(last visited June 22, 2009).</p>'+ 
    '</div>'+ 
    '</div>'; 



    var markers = []; 

    locations = [{lat: -24.363, lng: 131.044}, {lat: -20.363, lng: 136.044}, {lat: -25.363, lng: 118.044}, {lat: -27.363, lng: 138.044}, {lat: -28.363, lng: 130.044}]; 
    titles = ['rock', 'Alpha', 'beta', 'gamma', 'neta']; 


    for (var i = 2; i >= 0; i--) { 
     markers[i] = new google.maps.Marker({ 
     position: locations[i], 
     map: map, 
     title: titles[i], 
     mytype: 1 
     }); 
    } 

    for (var k = 4; k >= 3; k--) { 
     markers[k] = new google.maps.Marker({ 
     position: locations[k], 
     map: map, 
     title: titles[k], 
     mytype: 0 
     }); 
    } 

    var infowindow = new google.maps.InfoWindow(); 


      function myclosure(j) { 
      return function() { 
       infowindow.setContent(contentString[j]); 
       infowindow.open(markers[j].get('map'), markers[j]); 
      } 
      } 
      for (var j = 4; j >= 0; j--) {  
       markers[j].addListener('click', myclosure(j));  
     } 





    document.getElementById("second-tab").addEventListener('click', function() { 

     for (var i = 2; i >= 0; i--) { 
     markers[i].setMap(null); 
     } 
     for (var i = 4; i >= 3; i--) { 
     markers[i].setMap(map); 
     } 
    }); 

    document.getElementById("first-tab").addEventListener('click', function() { 
     for (var i = 4; i >= 3; i--) { 
     markers[i].setMap(null); 
     } 
     for (var i = 2; i >= 0; i--) { 
     markers[i].setMap(map); 
     } 
    }); 
    document.getElementById("third-tab").addEventListener('click', function() { 
     for (var i = 4; i >= 0; i--) { 
     markers[i].setMap(map); 
     } 

    }); 

} 
</script> 
<script async defer 
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBga3chd-auBMGLGITc3rjact16mozcI4Q&callback=initMap"> 
</script> 
</body> 
</html> 

:このために私は次のコードを使用していました。ループの代わりに手動で以下を実行する場合:

   markers[0].addListener('click', function(){ 
       infowindow.setContent(contentString[0]); 
       infowindow.open(markers[0].get('map'), markers[0]); 
}); 

マーカー[0]のインフォウィンドウが正常に動作します。したがって、

なぜmyclosure関数は期待どおりに機能しませんか?

編集:それはむしろ、イベントリスナー内で機能myclosureを呼び出して、私はすぐに呼び出された関数内でイベントリスナーを使用する必要があることが示唆されています。しかし、私の方法はなぜ機能しないのですか?私はシンプルなDOM要素についても同じアプローチを試してみました。ここで私が試したコードは次のとおりです。

var cont = document.getElementById("container"); 
 

 
function myclosure(i){ 
 
    return function(){ 
 
     alert("test" + i); 
 
    } 
 
    } 
 

 
    for (var i = 1; i >= 0; i--) { 
 
     cont.getElementsByTagName("div")[i].addEventListener("click",myclosure(i)); 
 
    }
* { 
 
     margin: 0; 
 
     padding: 0; 
 
     box-sizing: border-box; 
 
    }  
 
    #container { 
 
     width: 100%; 
 
     background-color: #ffff12; 
 
    } 
 
    .one, .two { 
 
     padding: 10px; 
 
     } 
 
    .one { 
 
     background-color: #777; 
 
    } 
 
    .two { 
 
     background-color: #aaa; 
 
    }
<div id="container"> 
 
     <div class="one">first</div> 
 
     <div class="two">second</div> 
 
    </div>

私はGoogleマップで使用されるように、私はまったく同じアプローチを使用しています。

なぜこのコードは動作しますが、Googleマップコードではありませんか?

for (j in) { 
      markers[j].addListener('click', myclosure(j)); 
    } 

実行することができます。

答えて

0

私はこのコードがどのような状況を知りません。正しく動作させるには、

for (j in markers) { 
      markers[j].addListener('click', myclosure(j)); 
    } 

のようにする必要があります。アレイをループするために使用できる方法はいくつかあります。 for..inで問題が発生した場合は、配列をループするように設計されたforEachを使用できます。このセクションでは

+0

問題の原因となっているコードの分離された部分でフィドルを作成できますか? – Cheitan

+0

jsfiddleにgoogleのapiスクリプトを追加する方法がわかりません。コード全体をhtmlファイルとして保存して実行することができます。 – user31782

+0

投稿したコード全体をテストする際にエラーが発生することはありません。これを直接試すときに問題がありますか?まったく同じコードを投稿していないかもしれませんが、このコードはChromeとFFでは機能しているようです。 – Cheitan

2

あなたはmyclosure()を呼び出すため、ハンドラとして返されるもの渡している

for (var j = 4; i >= 0; i--) { 
     markers[j].addListener('click', myclosure(j)); 
} 

なく、関数自体

は私が気づい

for (var j = 4; i >= 0; i--) { 
    (function(j) { 
    markers[j].addListener('click', function() { 
     myclosure(j); 
    }); 
    })(j); 
} 
+0

私もこれを試しました。しかし、それはまだ動作しません。私は 'myclosure(j)'関数に 'alert(j)'を追加しました。 – user31782

+0

問題を再現するデモを作成する – charlietfl

+0

ところで、マーカー[j] .addListener( 'click'、myclosure(j)) 'の' myclosure(J) 'は実行され、結果はイベントリスナーに割り当てられる、関数の定義だけが割り当てられていますか? – user31782

0

2つのことを試してみてください。ループ内でaddListener()コールw.r.t結合

  1. スコープ:

    for (var j = 4; j >= 0; j--) { 
        markers[j].addListener('click', function() { 
        myclosure(j); 
        }); 
    } 
    

    あなたのEventHandlerコールバック関数内jにアクセスしようとしています。このイベントハンドラはマーカーをクリックしたときにのみ実行されます。その場合、jは、コンテキストが変更されたときに-1になります。これを修正するには、次に行うことがあります。

    for (var j = 4; j >= 0; j--) { 
        markers[j].idx = j; 
        markers[j].addListener('click', (function() { 
        myclosure(this.idx); 
        }).bind(markers[j])); 
    } 
    

    プロパティとしてmarker[j]にインデックス値を追加しなeventHandlerにバインドします。これにより、実行時に正しい値が使用されます。あなたがmarker[j]を変異させたくない場合はしかし、その後、あなたにも、このよう上記の操作を行うことがあります。

    for (var j = 4; j >= 0; j--) { 
        markers[j].addListener('click', (function() { 
        myclosure(this); 
        }).bind(j)); 
    } 
    
  2. 上記の変更は、まだあなたのmyclosure(j)が仕事を得るためにそこに半分の方法です。 myclosure(j)は、決して呼び出されない関数を返しています:)これを修正するには、最終的なコードは次のようになります。

    function myclosure(j) { 
        return function() { 
        infowindow.setContent(contentString[j]); 
        infowindow.open(markers[j].get('map'), markers[j]); 
        }; 
    } 
    
    for (var j = 4; j >= 0; j--) { 
        markers[j].addListener('click', (function() { 
        myclosure(this)(); 
        }).bind(j)); 
    } 
    

    それをさらに簡単にするために、あなたは上記のように書き換えることがあります。この場合

    function myclosure(j) { 
        return function() { 
        infowindow.setContent(contentString[j]); 
        infowindow.open(markers[j].get('map'), markers[j]); 
        }; 
    } 
    
    for (var j = 4; j >= 0; j--) { 
        markers[j].addListener('click', myclosure(j)); 
    } 
    

    、我々はjが有効な値ことに関連してmyclosure()を呼び出すです。 addListener()functionがeventHandlerとしてバインドされることを想定しているので、myclosure(j)によって返された関数をバインドします。返された関数は、マーカークリック時にmyclosure(j)によって提供されるスコープ内で実行されます。jは、ループ内でmyclosure(j)という即時呼び出しの結果として有効です。

閉鎖の実行についての疑問を明確にすることを希望します。

Working JSFiddle JSFiddleのようにinitMap()の実行を変更する必要がありました。マップapi呼び出しのコールバックパラメータとして実行するのに問題がありました。

+0

1.私は決して 'for(var j = 4; j> = 0; j--){ markers [j] .addListener( 'click 3.あなたのリンクしている作業フィドルは、私の質問と同じコードを使用しています。3.私のコードは常に正しいと思われます;それは働いています。 – user31782

+0

ああ、私があなたの質問に気付いたのは、**すでにmyclosure(j)コールを使用していたからです。ディテールを変更しましたが、あなたのフィドルコードは私が行った変更を説明するためだけに使用していましたので、 'maters [j]'は未定義です配列に決して値が割り当てられていない場合にのみ発生します – v1p

+0

なぜ一つのことが働いているのか、なぜ他のものがなぜではないのかについての説明を聞いています。とにかにこれがもはや問題でなければ、完了した質問に印を付けてください。自分の答えを投稿して受け入れます。 – v1p

0

JQueryを使用する場合は、一意のID属性を持つ各マーカーにクラスを追加し、クラスセレクターを使用してクリックイベントリスナーを追加するだけです。

 
`$(".marker").on("click",function(){ 
    var _id = $(this).attr('id'); 
    $(_id+"_infobox").show(); 
});`

idを使用すると、その特定の情報ボックスを挿入または開くことができます。

関連する問題