Как использовать Angular директивы ng-click и ng-class внутри всплывающего маркера Leaflet - программирование

Как использовать 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>

Однако, когда я нажимаю значок, ничего не происходит, и он не выглядит так, как вызываются функции. Кто-нибудь знает, почему это произойдет?

4b9b3361

Ответ 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
};

Надеюсь, это поможет!