Как отмечено в комментариях к вопросу, у вас есть проблема с областью действия вашего итератора индекса i
, и не должно быть никаких технических проблем при интеграции Leaflet с Meteor (хотя с Blaze это может быть не совсем тривиально и не интересно).
1.Проблема области итерации
Консоль сообщает мне, что currentVenue
это undefined
.
Это потому, что вы пытаетесь получить доступ к fsqresults[i].properties.name
в вашем container.on('click'
прослушиватель событий / обратный вызов, который будет вызываться по щелчку пользователя, т. Е. после завершения ваш цикл for
завершен, следовательно, ваша переменная итератора индекса i
будет равна fsqresults.length
.
Вы в случае примера 6 приняли ответ: Как работают замыкания JavaScript?
2.Интеграция листовки с Meteor (Blaze)
Поскольку вы упомянули, что пытались использовать помощников, события и {{#each markers}}
, я предполагаю, что вы используете Blaze в качестве движка рендеринга Meteor.
Хотя React-Leaflet и Vue2Leaflet действительно предлагают возможность использовать своего рода компонент "<Marker>
" (такой же для других типов слоя Leaflet), последний предназначен только для целей объявления шаблона, т.е.он не отображает напрямую DOM / HTML, а только вызывает некоторые методы Leaflet, которые будут отвечать за управление DOM.Как указано в React-Leaflet ограничения :
Представленные компоненты являются абстракциями для слоев Leaflet, а не для элементов DOM.
Примечание: интересно видеть, что angular-leaflet-директива и @ asymmetrik / ngx-leaflet не попали в одно и то же искушение и придерживались JS-декларации слоев Leaflet.
Поэтому попытка создать Template.Marker
(используется как {{> Marker}}
) в Blaze может быть излишней, так как вы просто вызываете некоторые фабрики Leaflet (например, L.marker
) в пределах вашего Template.Marker.onCreated
(и нуждаетесь в доступе).каким-то образом родительский объект map
для добавления вашего маркера в…), без рендеринга какого-либо узла DOM самостоятельно (т. е. у вас будет HTML-файл с пустым <template name="Marker"></template>
).
Хотя мы забудем о шаблоне маркера вBlaze (как вы уже сделали), мы все еще можем использовать управление событиями Blaze для обработки пользовательских кликов в вашем всплывающем окне Leaflet.Для этого нам понадобится несколько функций Blaze, которые, как я признаю, могут быть лучше документированы:
- Мы можем присоединить произвольные данные JS к нашему экземпляру шаблона .
- События шаблона делегированы , поэтому нам не нужно прикреплять их к каждому
<button>
перед передачей. - Мы можем легко получить доступ к экземпляру шаблона в обработчиках событий (как второй аргумент слушателя события).
2.1.Присоединение произвольных данных JS к нашему экземпляру шаблона
Как указано в API экземпляров шаблона :
[…], вы можете назначить дополнительные свойства вашегоВыбор объекта.Используйте методы onCreated
и onDestroyed
для добавления обратных вызовов, выполняющих инициализацию или очистку объекта.
Поэтому вы можете хранить fsqresults
в своем экземпляре Template, чтобы вы могли получить доступпозже (обычно в вашем слушателе событий):
Template.myTemplate.onRendered(function () {
this.autorun(() => { // Using an arrow function to keep the same `this`, but you could do `const self = this` beforehand.
const fsqresults = this.fsqresults = FsqResults.find().fetch();
});
});
Но так как мы хотим получить доступ к определенным функциям позже, может быть более интересно преобразовать fsqresults
в словарь.Поскольку ваш идентификатор выглядит как feature.properties.name
, вы можете сделать:
Template.myTemplate.onCreated(function () {
this.autorun(() => {
const fsqresults = this.fsqresults = FsqResults.find().fetch();
const markersDict = this.markersDict = {};
L.geoJSON(fsqresults, {
pointToLayer(feature, latlng) {
const props = feature.properties;
const markerName = props.name;
// Save a direct reference to the Feature data,
// using the `markerName` as key (ID).
markersDict[markerName] = feature;
// Store the `markerName` in the button `dataset`
// (i.e. as a `data-` attribute),
// as already suggested in the question comments,
// so that we can easily retrieve the ID / key
// of the Marker data associated with the button the user clicked on.
return L.marker(latlng).bindPopup(`
<p>${markerName}</p>
<button role="popupClick" data-marker-name="${markerName}">
Popup action
</button>
`);
},
});
});
});
2.2.Делегирование обработчика событий шаблона
Как указано в Подробные сведения о Blaze :
Механизм DOM […], который имеет […] делегирование события
(извините, в официальном документе нет никаких других упоминаний об этой функции ... дайте мне знать, если вы найдете лучший вариант!)
Therпоэтому, пока мы создаем обработчик события Template с соответствующим селектором, нам не нужно прикреплять прослушиватель событий к каждой кнопке, который в любом случае мы не можем создать как узел, а оставить его как String, переданный Leaflet .bindPopup
(как сделано в приведенном выше примере кода).
Например:
Template.myTemplate.events({
// Even if the `<button role="popupClick">` are not DOM nodes yet
// (because Leaflet will create them from the HTML String
// only when the user opens the popup by clicking on the Marker),
// the "click" event will bubble up to the template instance,
// which will call this event handler if it matches the selector.
'click button[role="popupClick"]'() {
console.log('clicked on a button that has been built in a Leaflet Popup');
}
});
2.3.Получите доступ к экземпляру шаблона и нашим данным Feature
Обработчик события Blaze вызывается с дополнительным вторым аргументом , который является текущим экземпляром шаблона:
Функция-обработчик получает два аргумента: event
, объект с информацией о событии, и template
, экземпляр шаблона для шаблона, в котором определен обработчик.
Поэтому в нашемВ этом случае мы можем легко получить переменную markersDict
, которую мы определили в onCreated
, и использовать ее для получения точных данных функции маркера, связанных с кнопкой, на которую нажал пользователь:
Template.myTemplate.events({
'click button[role="popupClick"]'(event, templateInstance) {
const button = event.currentTarget;
const markerName = button.dataset.markerName;
const markerFeature = templateInstance.markersDict[markerName];
// Do something with `markerFeature`…
console.log(markerFeature);
}
});
Если вы тольковам нужно свойство name
, тогда вы можете даже пропустить шаг 2.1 и напрямую использовать строку markerName
, полученную из набора данных <button>
.