@JackDrakkar

Как отлавливать angular ng-click из элемента circle, созданного с помощью Snap.svg?

Есть следующий код:
angular.module('app', [])
    .controller('AppController', AppCtrl)
    .factory('Field', function(){
        return{
        Init: InitGroup
        }
    });


function InitGroup(Style) {
    var col = 2;
    var row = 3;
    var dist = 24;

    var circleGroup = Snap('#svgGroup');

    for (var i = 1; i <= col; i++) {
        for (var j = 1; j <= row; j++) {
            var circle = circleGroup.circle(dist * i, dist * j, dist / 3).attr(Style.transparent);
            circle.attr({id: i * j, col: i, row: j, 'ng-click': "circleClicked()"});
        }
    }
}


AppCtrl.$inject = ['$scope', 'Field'];
function AppCtrl($scope, Field){
    var Style = {
        transparent:{
            fill: 'transparent',
            stroke: '#000000',
            strokeWidth: 1
        },
        blue:{
            fill: '#000099',
            stroke: '#000000',
            strokeWidth: 1
        }
    };
    
    Field.Init(Style);

    $scope.circleClicked = function(){
        console.log('circle clicked');
    };
}


Получается страница со следующим кодом:
<!DOCTYPE html>
<html lang="en" ng-app="app">
<head>
    <meta charset="UTF-8">
    <script type="text/javascript" src="angular.js"></script>
    <script type="text/javascript" src="snap.svg-min.js"></script>
    <script type="text/javascript" src="index.js"></script>
    <title></title>
    <style>
        #svg{
            border: 1px solid black;
        }
    </style>
</head>
<body>
<div ng-controller="AppController">
 <svg version="1.1" id="svgGroup" xmlns="http://www.w3.org/2000/svg" width="200px" height="200px" viewBox="0 0 200 200">
        <desc>Created with Snap</desc>
        <defs></defs>
        <circle cx="24" cy="24" r="8" fill="rgba(0,0,0,0)" stroke="rgba(0,0,0,0)" id="1" col="1" row="1" ng-click="circleClicked()" style="stroke-width: 1px;"></circle>
        <circle cx="24" cy="48" r="8" fill="rgba(0,0,0,0)" stroke="rgba(0,0,0,0)" id="2" col="1" row="2" ng-click="circleClicked()" style="stroke-width: 1px;"></circle>
        <circle cx="24" cy="72" r="8" fill="rgba(0,0,0,0)" stroke="rgba(0,0,0,0)" id="3" col="1" row="3" ng-click="circleClicked()" style="stroke-width: 1px;"></circle>
        <circle cx="48" cy="24" r="8" fill="rgba(0,0,0,0)" stroke="rgba(0,0,0,0)" id="4" col="2" row="4" ng-click="circleClicked()" style="stroke-width: 1px;"></circle>
        <circle cx="48" cy="48" r="8" fill="rgba(0,0,0,0)" stroke="rgba(0,0,0,0)" id="5" col="2" row="5" ng-click="circleClicked()" style="stroke-width: 1px;"></circle>
        <circle cx="48" cy="72" r="8" fill="rgba(0,0,0,0)" stroke="rgba(0,0,0,0)" id="6" col="2" row="6" ng-click="circleClicked()" style="stroke-width: 1px;"></circle>
 </svg>
</div>
</body>
</html>


Пример упрощен, т.к. код генерирует столько, сколько укажет пользователь.

Проблема в том, что (как и ожидалось) ng-click в данном случае не отлавливает в контроллере, т.к. (как я понял) angular просто даже не знает об этих объектах.

Гугление по этому вопросу привело к очень слабо описанным примерам, где элементы создаются с помощью .directive. На подобие этого:
angular.module('SvgMapApp').directive('svgMap', ['$compile', function ($compile) {
    return {
        restrict: 'A',
        templateUrl: 'img/Blank_US_Map.svg',
        link: function (scope, element, attrs) {
            var regions = element[0].querySelectorAll('.state');
            angular.forEach(regions, function (path, key) {
                var regionElement = angular.element(path);
                regionElement.attr("region", "");
                $compile(regionElement)(scope);
            })
        }
    }
}]);

angular.module('SvgMapApp').directive('region', ['$compile', function ($compile) {
    return {
        restrict: 'A',
        scope: true,
        link: function (scope, element, attrs) {
            scope.elementId = element.attr("id");
            scope.regionClick = function () {
                alert(scope.elementId);
            };
            element.attr("ng-click", "regionClick()");
            element.removeAttr("region");
            $compile(element)(scope);
        }
    }
}]);


Связывание angular и snap.svg объекта создается через $compile (компилирование?) строки каждого объекта, тем самым сообщая angular о его существовании?
Но в данном случае (как я понял) у автора есть ограниченное количество заранее определенных элементов с классом .state.

Но каким образом можно динамически создавать такой объект и связывать с аangular, что бы в дальнейшем работать с ним (и с множеством объектов)?

Вроде как видел где-то вот такое:
var obj = new directiveName();
или на подобие этого. Суть в том что в контроллере через new создавался новый объект используя шаблон directive. Вроде как нет ничего невозможного, но может знающие люди помогут выйти из сложившейся ситуации :)
  • Вопрос задан
  • 578 просмотров
Пригласить эксперта
Ответы на вопрос 1
Fesor
@Fesor
Full-stack developer (Symfony, Angular)
зачем такие сложности? Просто сделайте директивку и там работайте с DOM, навесьте ивент листенер и пробросте клик уже как экшен какой-то.

ng-click удобный примитив, но если вы начинаете пихать какие-то страшные вещи типа $compile только для того что бы клики обрабатывать и у вас не стандартный ангуляровский темплейт а просто какой-то кусок DOMа - то лучше сделать проще.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы