I draw several elements in svg (using ng-switch
) and handle mouse events on them. The controller looks like this (there are much more types of elements and more mouse events to handle):
app.controller('MainCtrl', function($scope) {
$scope.elements = [
{ "type": "circle", "x" : 100, "y" : 200 },
{ "type" : "rect", "x" : 50, "y" : 20 }
];
$scope.mousedown = function(element, $event) {
$scope.msg = element.type;
};
});
Inside the mouse event handler, I need the model of the target of the mouse event.
My current solution is to add ng-mousedown="mousedown(element, $event)"
to each svg element, which is annoying for a growing number of element types.
<g ng-switch="p.type">
<g ng-switch-when="circle">
<circle ng-mousedown="mousedown(p, $event)"></circle>
</g>
<g ng-switch-when="rect">
<rect ng-mousedown="mousedown(p, $event)"></rect>
</g>
</g>
Is there a way to add ng-mousedown
only to the root svg element and retrieve the model of the clicked element from the $event
properties ($event.target
or $event.srcElement
gives me the clicked svg element, how to get the model from this?).
Complete example:
I draw several elements in svg (using ng-switch
) and handle mouse events on them. The controller looks like this (there are much more types of elements and more mouse events to handle):
app.controller('MainCtrl', function($scope) {
$scope.elements = [
{ "type": "circle", "x" : 100, "y" : 200 },
{ "type" : "rect", "x" : 50, "y" : 20 }
];
$scope.mousedown = function(element, $event) {
$scope.msg = element.type;
};
});
Inside the mouse event handler, I need the model of the target of the mouse event.
My current solution is to add ng-mousedown="mousedown(element, $event)"
to each svg element, which is annoying for a growing number of element types.
<g ng-switch="p.type">
<g ng-switch-when="circle">
<circle ng-mousedown="mousedown(p, $event)"></circle>
</g>
<g ng-switch-when="rect">
<rect ng-mousedown="mousedown(p, $event)"></rect>
</g>
</g>
Is there a way to add ng-mousedown
only to the root svg element and retrieve the model of the clicked element from the $event
properties ($event.target
or $event.srcElement
gives me the clicked svg element, how to get the model from this?).
Complete example: http://plnkr.co/edit/nfgVSBBaeJ9EFKNjYEJn
Share asked Dec 19, 2013 at 9:04 hansmaadhansmaad 18.9k9 gold badges56 silver badges97 bronze badges2 Answers
Reset to default 5Yes, you can use angular.element(...).scope().p
as follows:
Markup:
<svg xmlns="http://www.w3/2000/svg" ng-mousedown="mousedown2($event)">
JS:
$scope.mousedown2 = function($event) {
console.log(angular.element($event.target).scope().p);
});
See forked plunk: http://plnkr.co/edit/7lGMphla42Chrg3X2NZl
Since element.scope()
relies on debug data, it's not a solution for production mode. In a more plex case, you have to write a directive that sets the "event source" which then can be handled by another directive on a parent element if the event bubbles up (see 2nd example below).
In this particular case the solution is very simple if you put the event handler on the ng-repeat
element like this:
angular.module("app", [])
.controller('MainController', MainController);
function MainController() {
var vm = this;
vm.elements = [
{ "type": "circle", "x" : 100, "y" : 100 },
{ "type" : "rect", "x" : 50, "y" : 20 }];
vm.mousedown = function(element, $event) {
vm.msg = element.type;
};
}
<script src="https://ajax.googleapis./ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="MainController as view">
<svg xmlns="http://www.w3/2000/svg" width="300" height="120">
<g ng-repeat="p in view.elements" ng-switch="p.type"
ng-mousedown="view.mousedown(p, $event)">
<circle ng-switch-when="circle"
ng-attr-cx="{{p.x}}" ng-attr-cy="{{p.y}}" fill="red" r="20">
</circle>
<rect ng-switch-when="rect"
ng-attr-x="{{p.x}}" ng-attr-y="{{p.y}}" width="50" height="50" fill="blue" >
</rect>
</g>
</svg>
<p>
{{view.msg}}
</p>
</div>
More plex example
This example shows the usage of two directives eventSource
and eventHandler
. eventHandler
listens on events on the root element. eventSource
registers "event sources" on its controller.
angular.module("app", [])
.controller('MainController', MainController)
.directive('eventSource', eventSource)
.directive('eventHandler', eventHandler);
function MainController() {
var vm = this;
vm.elements = [
{ "type": "circle", "x" : 100, "y" : 80 },
{ "type" : "rect", "x" : 50, "y" : 20 }
];
vm.rect = { "type" : "special", "x" : 0, "y" : 40 };
vm.handle = function(element, $event) {
vm.msg = $event.type + ': ' + element.type;
};
}
function eventSource($parse) {
return {
restrict: 'A',
require: '^eventHandler',
link: function (scope, elem, attr, controller) {
var sourceAttr = attr['eventSource'];
var source = $parse(sourceAttr)(scope);
controller.register(elem, source);
scope.$on('$destroy', function () {
controller.unregister(elem);
});
}
};
}
function eventHandler() {
return {
restrict: 'A',
scope: {
eventHandler: '&'
},
controller: function () {
var vm = this;
vm.sources = [];
this.register = function (element, source) {
vm.sources.push({element : element, source: source});
}
this.unregister = function (element) {
var i = 0;
for(var e = vm.sources.length; i < e; ++i) {
if (vm.sources[i].element === element)
break;
}
vm.sources.splice(i, 1);
}
},
link: function (scope, elem, attr, controller) {
elem.on('mousedown mouseup', function ($event) {
var target = $event.target;
while (target && !target.hasAttribute('event-source'))
target = target.parentNode;
for(var i = 0, e = controller.sources.length; i < e; ++i) {
if (controller.sources[i].element[0] === target) {
scope.eventHandler({element : controller.sources[i].source, $event : $event});
}
}
scope.$apply();
});
}
};
}
<script src="https://ajax.googleapis./ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="MainController as view">
<svg xmlns="http://www.w3/2000/svg" width="300" height="120"
event-handler="view.handle(element, $event)">
<g ng-repeat="p in view.elements" ng-switch="p.type"
event-source="p">
<circle ng-switch-when="circle"
ng-attr-cx="{{p.x}}" ng-attr-cy="{{p.y}}" fill="red" r="20">
</circle>
<rect ng-switch-when="rect"
ng-attr-x="{{p.x}}" ng-attr-y="{{p.y}}" width="50" height="50" fill="blue" >
</rect>
</g>
<rect ng-attr-x="{{view.rect.x}}" ng-attr-y="{{view.rect.y}}" width="80" height="50" fill="green"
event-source="view.rect">
</rect>
</svg>
<p>
{{view.msg}}
</p>
</div>