Здравствуйте!
Уже пару часов бьюсь лбом об стену :)
У меня есть БД с таблицей, в которой хранятся данные о локациях (поля id, location, start, end, description). В колонке location хранится place_id из
Google Maps API, по которому эта самая апи может найти локацию и нанести ее на карту (маркером).
По условиям задачи, в течении одного захода на страницу количество записей в таблице может изменяться (записи могут быть изменены, удалены или добавлены). Поэтому было решено, что за создание карты, создание перечня маркеров и за показы этих маркеров будут отвечать три разные функции в javascript'e.
$(document).ready(function()
{
// создает карту
var map = create_map();
// создает маркеры, не отображая их
var markers = create_markers(map);
// показывает, что объекты в массиве есть (об этом читайте далее)
console.log(markers);
// показывает 0 (об этом читайте далее)
console.log(markers.length);
// включает отображение маркеров
setAllMap(map, markers);
});
Собственно, создание карты нехитрое:
function create_map() {
var mapOptions = {
center: {lat: 0, lng: 0},
zoom: 1
};
var map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
return map;
}
А вот массив, в котором лежат объекты-маркеры получается путем обращения к php-скрипту, который вытягивает и отдает в js массив с данными из базы. Далее этот массив обрабатывается, и на выходе получаем нужные объекты-маркеры.
function create_markers(map) {
console.log("create_markers_start");
var service = new google.maps.places.PlacesService(map);
var infowindow = new google.maps.InfoWindow();
var markers = [];
$.ajax({
async: false,
url: '/index.php/locations/get_locations_list_json',
success: function(locations_json) {
console.log("create_markers___ajax_success_start");
var locations = $.parseJSON(locations_json);
$.each(locations, function(i, location_point) {
var request = {
placeId: location_point.location
};
Date.prototype.getMonthName = function() {
var month = ['Jan','Feb','Mar','Apr','May','Jun', 'Jul','Aug','Sep','Oct','Nov','Dec'];
return month[this.getMonth()];
}
var desc = location_point.description;
var start_obj = new Date(location_point.start);
var start = start_obj.getMonthName() + " " + start_obj.getDate();
var end_obj = new Date(location_point.end);
var end = end_obj.getMonthName() + " " + end_obj.getDate();
service.getDetails(request, function(place, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
markers[i] = new google.maps.Marker({
map: null,
position: place.geometry.location
});
google.maps.event.addListener(markers[i], 'click', function() {
infowindow.close();
infowindow.setContent('<div><strong>' + place.name + '</strong><br>' +
'You\'re going to visit <u>' + place.formatted_address + '</u>' +
' <b>from</b> ' + start +
' <b>to</b> ' + end +
'<br><br>' + desc);
infowindow.open(map, this);
});
}
});
});
}
});
console.log("create_markers_end");
return markers;
}
Проблема в следующем: к моменту запуска
setAllMap в массиве markers пусто (хотя выше по тексту была функция, которая его должна была заполнить.
Что характерно. Как видите, по тексту расставлены консоль.логи. Ниже показан лог (можно увидеть последовательность выполнения скриптов, а также вывод markers и markers.length:
create_markers_start
create_markers___ajax_success_start
create_markers_end
var_markers
Array[7]
0
В Array[7] можно наблюдать нужные объекты-маркеры. Но, как видите, в это же момент markers.length показывает ноль. Полагаю, это связано с особенностями логирования. Также полагаю, что это связано с тем, что в коде используется вызов ajax'a (который я сделал синхронным, но не помогло).
Как решить проблему? Как сделать, чтобы к моменту запуска функции
setAllMap(map, markers) в переменной markers уже был нужный нам массив?
Спасибо.
З.Ы. Для работы всего этого к странице подключена библиотека
Google Maps для JS.
---
UPDATE
Спасибо
Максим, вопрос с очередностью запуска решено. Но появилась (вернее, не решилась) такая проблема: markers.length по-прежнему равен нулю!
Вот код вызова:
create_markers(map, function(markers) {
console.log("in `create_markers`: markers: ");
console.log(markers);
console.log("in `create_markers`: markers.length: ");
console.log(markers.length);
// включает отображение маркеров
setAllMap(map, markers);
});
Вот код функции:
function create_markers(map, fn) {
var markers = {}
$.ajax(..., {
success: function(...) {
...
console.log("markers: ");
console.log(markers);
console.log("markers.length: ");
console.log(markers.length);
fn(markers);
}
});
}
А вот консоль:
markers:
Array[7]
markers.length:
0
in `create_markers`: markers:
Array[7]
in `create_markers`: markers.length:
0
---
UPDATE 2
Проблема решена следующим образом:
function create_markers(map, fn) {
...
var markers_array = [];
var promises_array = [];
$.ajax({
...
success: function(...)
{
$.each(..., function(...) {
// отслеживаем состояние асинхронного запроса
var dfd;
dfd = new $.Deferred();
// это асинхронный запрос, для его правильной обработки используем промисы
service.getDetails(..., function(...) {
var marker = ...;
// по завершению формирования маркера отправляем его в массив
markers_array.push(marker);
// затем помечаем, что асинхронный запрос завершился успехом
dfd.resolve();
});
// отправляем отчет об успешном завершении очередного асинхронного запроса в массив с промисами
promises_array.push(dfd.promise());
});
// если все асинхронные вызовы завершились - вызываем callback
$.when.apply($, promises_array).then(function(){
fn(markers_array);
});
}
});
}
$(document).ready(function()
{
...
create_markers(map, function(markers_array) {
...
});
});