Add onclick listener to Google Maps Markers JavaScript

I wrote this code:

<script type="text/javascript">
    var address = JSON.parse('<?php echo $jsonLocations ?>');
    console.log(address.locations[0]);
    var latitude = '1';
    var longitude = '1';

    function initMap() {
        var map = new google.maps.Map(document.getElementById('map'), {
            zoom: 12,
            center: new google.maps.LatLng(latitude, longitude)
        });
        for(var i = 0; i < address.locations.length; i++){

            new google.maps.Marker({
                position: new google.maps.LatLng(address.locations[i]['lat'], address.locations[i]['long']),
                map: map
            }).addListener('click', function(){
                new google.maps.InfoWindow({
                    content: '<div id="content">'+
            '<div id="siteNotice">'+
            '</div>'+
            '<h5>' + i +'</h5>'+
            '<div id="bodyContent">'+
            '</div>'+
            '</div>'
                }).open(map, this);
            })
        }
    }

</script>

I’m trying to display i onClick of the marker. So for the first maker I should be 0 and for the second 1. But somehow i is always the same value



This is a classic closure problem.
The function which is using the i variable is a async callback.

The first thing what is happening is, that all the markers will be created. Therefore i will be address.locations.length at the end of the loop.
The async callbacks now reference this exact variable.

There are some possible fixes for this:

use the let statement if you are able to use ES6 JavaScript features:

for(let i = 0; i < address.locations.length; i++){
    [...]
}

The second one is to create a closure with this exact binding:

for(var i = 0; i < address.locations.length; i++){
    (function(i){
        [...]
    })(i)
}

The last option for you is to use the Function.bind method.

for(var i = 0; i < address.locations.length; i++){

    new google.maps.Marker({
        position: new google.maps.LatLng(address.locations[i]['lat'], address.locations[i]['long']),
        map: map
    }).addListener('click', (function(i){
        new google.maps.InfoWindow({
            content: '<div id="content">'+
    '<div id="siteNotice">'+
    '</div>'+
    '<h5>' + i +'</h5>'+
    '<div id="bodyContent">'+
    '</div>'+
    '</div>'
        }).open(map, this);
    }).bind(this,i))
}

I hope that one of this methods will work for you.

This happens because the click event happens later in time and then i has the last value …

To fix this you can use a self invoking anonymous function inside the for loop – this way you will create a scope for each loop and the value of i will remain for the click when it happens.

This is called Closure – you can read more about closures here and here