Клуб API Карт

добавить адрес с геокодера в баллун в цикле

benedictus@tut.by
22 марта 2016, 15:59

Добрый день, в YMaps сижу пару дней, опыта нету, вопрос в селдующем:

страница при открытии забирает с реста json с массивом объектов, в каждом из которых, помимо прочей информации есть координаты широты и долготы.

необходимо в массиве разместить метки на карте в соответствии с координатами, а также в баллун, который открывается при нажатии наметку поместить адрес, полученный с Y геокодера, а также доп инфу с того же json-a. В моем решении адрес подтягивает только последняя метка (адрес тоже неверный ), остальные не реагируют никак. вот код js

var myMap;
        ymaps.ready(init);
        function init() {
            var markers=[];
            $.ajax({
                        url : 'rc/getalltrack/',
                        type : 'GET',

                        success : function(json) {
                                myMap = new ymaps.Map('map', {
                                center : [ json[0].lat, json[0].lng ],
                                zoom : 10
                            }, {
                                searchControlProvider : 'yandex#search'
                            });
                            for ( var i in json) {
                                markers.push(new ymaps.Placemark([ json[i].lat,
                                        json[i].lng ], {
                                

                                }, {
                                    preset : 'islands#icon',
                                    iconColor : '#0095b6'
                                }));

                                markers[i].events
                                        .add('click',function(e) {
                                                    ymaps.geocode(e.get('coords')).then(
                                                                    function(
                                                                            res) {
                                                                        var firstGeo = res.geoObjects
                                                                                .get(0);
                                                                        markers[i].properties
                                                                                .set({
                                                                                    balloonContent : firstGeo.properties
                                                                                            .get('text')
                                                                                });
                                                                    });
                                                });
                                myMap.geoObjects.add(markers[i]);
                            }
                            
                        }
                    });

        }

7 комментариев
Javascript – событийно ориентированный язык. На момент срабатывания обработчика клика цикл уже закончит свою работу и переменная "i" будет указывать на индекс последнего элемента массива.
Рекомендую прочитать про замыкания в javascript
benedictus@tut.by
22 марта 2016, 17:54
да, спасибо разобрался необходимо с помощью еще одного замыкания мы «затенить» переменную i, создавая ее копию в его локальной области видимости на каждом шаге цикла. (рецепт с хабра) итого бывший проблемный кусок выглядит так
(function(i){
markers[i].events
.add('click',function(e) {
ymaps.geocode(e.get('coords')).then(
function(
res) {
var firstGeo = res.geoObjects
.get(0);
markers[i].properties
.set({
balloonContent :

firstGeo.properties
.get('text')
});
});
});
myMap.geoObjects.add(markers[i]);
})(i);

еще раз спасибо за наводку
benedictus@tut.by,
Хорошо что вы разобрались. Лучше конечно не городить все это, а использовать делегирование событий. Вместо кучи обработчиков на каждую метку – вешаете один на коллекцию и получаете текущий объект, поймавший событие из обработчика как e.get('target')

var myMap;
ymaps.ready(init);

function init() {
var markers = [];
$.ajax({
url: 'rc/getalltrack/',
type: 'GET',

success: function(json) {
myMap = new ymaps.Map('map', {
center: [json[0].lat, json[0].lng],
zoom: 10
}, {
searchControlProvider: 'yandex#search'
});
for (var i in json) {
myMap.geoObjects.add(new ymaps.Placemark([json[i].lat,
json[i].lng
], {}, {
preset: 'islands#icon',
iconColor: '#0095b6'
}));
}
myMap.geoObjects.events
.add('click', function(e) {
// Текущая метка на которой произошло событие
var target = e.get('target');

ymaps.geocode(target.geometry.getCoordinates())
.then(function(res) {
var firstGeo = res.geoObjects.get(0);
target.properties.set({
balloonContent: firstGeo.properties.get('text')
});
});
});
}
});

}
benedictus@tut.by
24 марта 2016, 16:16
соглашусь, это решение более элегантное и менее ресурсоемкое, однако у меня вопрос возник с добавлением дополнительной информации которая приходит в json в баллун метки.
В моем текущем решении это реализовано так
(function(i) {
markers[i].events.add('click',function(e) { ymaps.geocode(e.get('coords')) .then(function(res) {var firstGeo = res.geoObjects
.get(0);
markers[i].properties
.set({
balloonContent : contentString(
json[i].name,
json[i].levelbat,
json[i].speed,
json[i].time)
+ '<span style="font-size:15px;">'
+ firstGeo.properties
.get('text')
+ '</span>'

});
});
});
myMap.geoObjects.add(markers[i]);
})(i);

в приведенном вами решении после размещения меток в цикле мы теряем с ними связь, которую в принципе можно восстановить, сопоставляя координаты объекта(метки) и координаты пришедшие c json (json[i].lat, json[i].lng), но этот вариант выглядит плохо, на мой взгляд правильнее будет добавить уникальный идентификатор к метке при размещении ее на карту (в нашем случае [i]) чтобы забирать данные напрямую из json а не перебором и сопоставлением координат. Я видел решение использовать metaDataProperty но не понял как применить конкретно к моей ситуации. Также предположительно в мое приложение будет добавляться возможность убрать/добавить произвольную метку с карты извне (например в панельке сбоку карты - чекбокс) или убрать/добавить группу меток с карты по определенному признаку. Вопрос идентификации меток все равно всплывет. Посоветуйте как решить.
benedictus@tut.by,
По этому коду не видно, что именно делает функция contentString, но мой совет – разделить HTML-разметку и данные, а не клеить их таким кривым образом.
В АПИ для этого существуют макеты.
https://tech.yandex.ru/maps/doc/jsapi/2.1/ref/reference/templateLayoutFactory-docpage/

В properties метки (второй параметр в конструкторе Placemark) надо положить все данные что есть (можно даже вместе с координатами) и в макете указать, что именно нужно выводить. После геокодирования вы просто добавляете к этим данным еще одно поле и оно отображается в балуне автоматически (макет содержимого балуна пересоберется)

https://jsfiddle.net/qup298n2/

PS: Не знаю, что именно делает ваше приложение, но на всякий случай – АПИ нельзя использовать для мониторинга транспорта, и в коммерческих целях.
benedictus@tut.by
24 марта 2016, 17:04
После долгих поисков нашел ответ https://yandex.ru/blog/mapsapi/53105 и здесь https://yandex.ru/blog/mapsapi/30616
benedictus@tut.by,
В данной задаче ничего сопоставлять не нужно, см. мой коммент выше