I'm interested in building a composite SVG by composing reusable graphical elements wrapped inside of Angular.js directives. For instance I might have:
<div ng-app="svgApp">
<canvas>
<drawing ng-repeat="i in [1,2,3]" cy="{{i * 40}}"></drawing>
</canvas>
</div>
where I am defining the following directives:
.directive('canvas', function () {
return {
template: '<svg height=200 width=100 ng-transclude></svg>',
restrict: 'E',
replace: true,
transclude: true
};
})
.directive('drawing', function () {
return {
template: '<circle cx=50 r=15></circle>',
restrict: 'E',
replace: true
};
})
The problem is that the SVG elements do not appear to get transcluded properly. A clue seems to be here, in another StackOverflow question that this is mostly because SVG nodes are not created properly within Angular.js.
After poking around further, I found this solution, which involves using a helper function to replace the relevant DOM elements with properly created SVG nodes, a la:
.value('createSVGNode', function(name, element, settings) {
var namespace = 'http://www.w3.org/2000/svg';
var node = document.createElementNS(namespace, name);
for (var attribute in settings) {
var value = settings[attribute];
if (value !== null && !attribute.match(/\$/) && (typeof value !== 'string' || value !== '')) {
node.setAttribute(attribute, value);
}
}
return node;
});
However, it seemed undesirable that I would need to use this everywhere, and I wanted to keep the workaround as local to the bug as possible, until it was fixed.
My question is whether the following would be a reasonable workaround:
angular.forEach(['circle', ...], function (svgElem) {
svgModule
.directive(svgElem, function (createSVGNode) {
return {
restrict: 'E',
link: function(scope, element, attrs) {
var node = createSVGNode(svgElem, element, attrs);
angular.element(node).append(element[0].childNodes);
element.replaceWith(node);
}
};
});
});
And this works in Plunker!
Is it valid for me to redefine existing SVG element directives in this way?