J
J
JackDrakkar2015-11-19 15:56:33
Angular
JackDrakkar, 2015-11-19 15:56:33

How to catch angular ng-click from circle element created with Snap.svg?

There is the following code:

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');
    };
}

This results in a page with the following code:
<!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>

The example is simplified because the code generates as many as the user specifies.
The problem is that (as expected) ng-click in this case does not catch in the controller, because (as I understand it) angular just doesn't even know about these objects.
Googling on this has resulted in very poorly documented examples where elements are created using .directive. Something like this:
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);
        }
    }
}]);

Is the binding of angular and the snap.svg of an object created via the $compile (compile?) line of each object, thus telling angular that it exists?
But in this case (as I understand it), the author has a limited number of predefined elements with the .state class.
But how can you dynamically create such an object and associate it with angular so that you can work with it (and with many objects) in the future?
It seems like I saw somewhere like this:
var obj = new directiveName();
or something like this. The bottom line is that in the controller through new a new object was created using the directive template. It seems like nothing is impossible, but maybe knowledgeable people will help to get out of this situation :)

Answer the question

In order to leave comments, you need to log in

1 answer(s)
S
Sergey, 2015-11-19
Protko @Fesor

why such difficulties? Just make a directive and work with the DOM there, hang an event listener and forward the click as some kind of action.
ng-click is a convenient primitive, but if you start to shove some terrible things like $compile just to process clicks and you don’t have a standard Angular template, but just some piece of DOM, then it’s better to make it simpler.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question