Reputation: 16059
How can I change the element associated with a call to transclude()
?
In my app, I dynamically load an entire SVG file from the server and display it. I need to add behaviors to the loaded content.
Currently, I have something like this:
<div svg-canvas="urlToSVGContent"></div>
This loads an SVG tag inside the div. This works great, but what if I want to add an ng-click to every <path>
, <circle>
, etc? ng-click
already works on svg paths out of the box, it's just a question of referencing the element somehow.
I can already make a directive using transclude that will run once for each path:
<div svg-canvas="urlToSVGContent">
<svg-each-path>
<!-- call transclude once per path found -->
</svg-each-path>
</div>
But inside svg-each-path, while I have a separate scope for each element, the el
parameter to the directive is meaningless. Or it still points to the parent div or something.
I would like to do this:
<div svg-canvas="urlToSVGContent">
<svg-each-path ng-click="onPathClick()">
</svg-each-path>
</div>
This is what svg-each-path
looks like currently:
function svgEachPath() {
return {
restrict: 'E',
transclude: 'element',
priority: 1000,
terminal: true,
link: link,
}
function link(scope, el, attrs, ctrl, $transclude) {
// scope.paths was set by the svg-canvas directive
scope.paths.forEach(function(path) {
var childScope = <InnerScope> scope.$new()
childScope.path = path
// how can I change "el" to point to path?
// or get the clone to be a clone of the path instead of the parent element?
$transclude(childScope, function(clone) {
})
})
}
}
Upvotes: 0
Views: 230
Reputation: 16059
I was looking for the $compile
service. It lets you take any html string or element, and bind it to a scope to run directives. It doesn't require transclude at all.
function svgEachPath($compile) {
return {
restrict: 'E',
// should stop processing directives. we don't want ng-click to apply to the fake element
terminal: true,
priority: 1000,
link: link,
}
function link(scope, el, attrs) {
scope.paths.forEach(function(path) {
// copy in all my attributes to the element itself
Object.keys(attrs)
.filter((key) => key[0] != "$")
.forEach((key) => {
// use snake case name, not camel case
path.attr(attrs.$attr[key], attrs[key])
})
// "compile" the element - attaching directives, etc
var link = $compile(path)
link(scope)
})
}
}
Usage:
<div svg-canvas="urlToSVGContent">
<svg-each-path ng-click="onPathClick(...)">
</svg-each-path>
</div>
Upvotes: 1