Как использовать Angular директивы ng-click и ng-class внутри всплывающего маркера Leaflet
Я использую Angular.JS и Leaflet.JS для карты в моем местоположении, у которой есть маркеры карт со связанными с ними всплывающими окнами. Мне нужно использовать диапазон с двумя разными значками (один из приведенных ниже в коде), которые вы можете щелкнуть, чтобы вызвать разные функции, и с ng-классом, чтобы изменить класс, если выполняются определенные условия. Это мой код:
var marker = L.marker([51.5, -0.09], {icon: blueIcon}).bindPopup('<br><span ng-class="thumbsUpClass(' + hotelsSelectedDates[i]['hotels'][s] + ')" ng-click="addChoice(' + hotelsSelectedDates[i]['hotels'][s] + ',' + hotels + ')"><span class="popup-container"><span class="icon-stack thumbs-up-stack"><i class="icon-sign-blank icon-stack-base"></i><i class="icon-thumbs-up"></i></span></span></span>');
Однако, когда я проверяю элемент, я получаю следующее:
<span ng-class="thumbsUpClass([object Object])" ng-click="addChoice([object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object])"><span class="popup-container"><span class="icon-stack thumbs-up-stack"><i class="icon-sign-blank icon-stack-base"></i><i class="icon-thumbs-up"></i></span></span></span>
ng-click должен отправить эту функцию как конкретному объекту, так и массиву объектов, но когда я нажимаю значок, ничего не происходит. В своем исследовании я обнаружил, что всплывающее окно предотвращает распространение событий (больше информации, но я не уверен, как его переопределить или исправить, чтобы работайте с Angular. У кого-нибудь есть идея, как это сделать?
UPDATE:
Так как ng-click/class оценивает строку, я фиксировал переменные следующим образом:
$scope.item = hotelsSelectedDates[i]['hotels'][s]
$scope.set = hotels
var marker = L.marker([51.5, -0.09], {icon: blueIcon}).bindPopup('<br><span ng-class="thumbsUpClass(item)" ng-click="addChoice(item,set)"><span class="popup-container"><span class="icon-stack thumbs-up-stack"><i class="icon-sign-blank icon-stack-base"></i><i class="icon-thumbs-up"></i></span></span></span>');
Затем html выходит правильно:
<span ng-class="thumbsUpClass(item)" ng-click="addChoice(item,set)"><span class="popup-container"><span class="icon-stack thumbs-up-stack"><i class="icon-sign-blank icon-stack-base"></i><i class="icon-thumbs-up"></i></span></span></span>
Однако, когда я нажимаю значок, ничего не происходит, и он не выглядит так, как вызываются функции. Кто-нибудь знает, почему это произойдет?
Ответы
Ответ 1
Ваша проблема связана с тем, что вы вручную создаете DOM, который не был скомпилирован AngularJS.
В этих случаях вам нужно вручную скомпилировать и связать элемент.
Код будет выглядеть так:
var html = '<br><span ng-class="thumbsUpClass(item)" ' +
'ng-click="addChoice(item,set)"><span class="popup-container"><span ' +
'class="icon-stack thumbs-up-stack"><i class="icon-sign-blank ' +
'icon-stack-base"></i><i class="icon-thumbs-up"></i></span></span></span>',
linkFunction = $compile(angular.element(html)),
newScope = $scope.$new();
newScope.item = hotelsSelectedDates[i]['hotels'][s]
newScope.set = hotels
var marker = L.marker([51.5, -0.09], {icon: blueIcon}).bindPopup(linkFunction(newScope)[0]);
Здесь я беру вашу строку HTML, и я начинаю с преобразования ее в DOM. Потому что AngularJS ест DOM, а не строки.
angular.element(html)
Затем я скомпилирую этот DOM в функцию ссылок, используя службу компиляции $.
linkFunction = $compile(angular.element(html));
При выполнении эта функция вернет дерево DOM jQuery, полностью контролируемое Angular, работающее в области, которую вы даете ему в качестве аргумента. Вот что я здесь делаю
linkFunction(newScope)
Обратите внимание, что область действия, которую я предоставляю, является дочерней областью $scope. Не делая этого, вы бы разделили ту же область между всеми всплывающими окнами, и это не было бы хорошей идеей. Создание новой области было сделано в объявлении var
newScope = $scope.$new()
Из этого вы можете получить фактический DOM node
linkFunction(scope)[0]
И передайте его в Листовку
.bindPopup(linkFunction(newScope)[0]);
И все готово!
Для получения дополнительной информации см. compiler doc.
РЕДАКТИРОВАТЬ: исправленные проблемы, касающиеся области
Ответ 2
Вы можете использовать новую поддержку для содержимого Angular в angular -leaflet-директиве:
var html = '<br><span ng-class="thumbsUpClass(item)" ' +
'ng-click="addChoice(item,set)"><span class="popup-container"><span ' +
'class="icon-stack thumbs-up-stack"><i class="icon-sign-blank ' +
'icon-stack-base"></i><i class="icon-thumbs-up"></i></span></span></span>';
...
$scope.markers.push( { lat: ...,
lng: ...,
message: html,
getMessageScope: function() { return $scope; },
});
Ответ 3
Я работал над этим конкретным типом проблемы, чтобы создать экземпляр функции с помощью щелчка внутри всплывающего окна. Я использовал директиву angular -leaflet, где я не мог выполнить компиляцию $, поскольку она уже находилась внутри компиляции $, и создавала бы циклическую ссылку. Я сделал следующее.
$scope.markers[$scope.asset_table[imc]['asset']['_id']['$oid']]={
lat:$scope.asset_table[imc]['last_data']['loc']['coordinates'][1],
lng:$scope.asset_table[imc]['last_data']['loc']['coordinates'][0],
focus:true,
message:"<h4>"+$scope.asset_table[imc]['asset']['name']+"</h4>
<span class='btn btn-danger'
onclick='detailView()';>View Details</span>",
//message: linkFunction, /*I discarded this as it was creating circular reference*/
icon: {
iconUrl: $scope.icon,
iconSize: [30, 30],
iconAnchor: [15, 15],
popupAnchor: [0, 0],
shadowUrl: $scope.icon,
shadowSize:[0,0],
iconAngle:$scope.asset_table[imc]['last_data']['bearing']
}
};
И ниже этого функция viewDetail() была вызвана
detailView = function(){
//alert("Test");
$rootScope.$broadcast('asset.details',$scope.asset_table);
}
Поэтому мне пришлось использовать традиционный javascript внутри angular, чтобы избежать сложной циклической привязки.
Ответ 4
Я немного опоздал на эту тему, но у меня была аналогичная ситуация и я хотел поделиться своим решением.
Предположим, что у вас есть html, который вы хотите добавить в свое всплывающее окно, просто добавьте в него 'id'.
var html = '<a id="popup" href="" ng-model="featureSelected" ng-click="cherryPickPin(featureSelected)">cherry pick this pin</a>';
теперь все, что вам нужно сделать, это:
var popupElement = $('#popup'); // grab the element (make sure that it exists in the DOM)
popupElement = $compile(popupElement)($scope); // let angular know about it
Ответ 5
Я пришел на этот пост, потому что искал решение этой проблемы на Ionic/Cordova (интеграция карт в мобильном приложении).
Проблема заключается в том, что функция $compute не работает, потому что она работает с облегченной версией jQuery. Таким образом, единственный способ, и, очевидно, самый простой, чтобы заставить его работать, - это код, предложенный Дэвидом (спасибо вам большое!).
В моем коде это выглядит так:
$scope.map.markers[i] = {
lat: parseFloat(place.latitude),
lng: parseFloat(place.longitude),
message: htmlPopupContent,
getMessageScope: function() { return $scope; },
focus: true,
draggable: false
};
Надеюсь, это поможет!
Ответ 6
Я нашел эту помощь для ответов для mapbox-gl-js и angular:
var html = '<button ng-click="fn()">Click Me</button>';
var compiledHtml = $compile(html)($scope);
var popup = new mapboxgl.Popup()
.setLngLat([-91.874, 42.760])
.setDOMContent(compiledHtml[0])
.addTo(map);
Включить ng-клик по всплывающей подсказке (mapbox)