title: AngularJS : Transcluding SVG elements in directives
body: <p>I'm interested in building a composite SVG by composing reusable graphical elements wrapped inside of Angular.js directives. For instance I might have:</p>
  
  <pre><code>&lt;div ng-app="svgApp"&gt;
    &lt;canvas&gt;
      &lt;drawing ng-repeat="i in [1,2,3]" cy="{{i * 40}}"&gt;&lt;/drawing&gt;
    &lt;/canvas&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>where I am defining the following directives:</p>
  
  <pre><code>  .directive('canvas', function () {
      return {
        template: '&lt;svg height=200 width=100 ng-transclude&gt;&lt;/svg&gt;',
        restrict: 'E',
        replace: true,
        transclude: true
      };
    })
  
    .directive('drawing', function () {
      return {
        template: '&lt;circle cx=50 r=15&gt;&lt;/circle&gt;',
        restrict: 'E',
        replace: true
      };
    })
  </code></pre>
  
  <p>The problem is that the SVG elements do not appear to get transcluded properly. A clue seems to be <a href="https://stackoverflow.com/questions/13641105/including-svg-template-in-angularjs-directive">here, in another StackOverflow question</a> that this is mostly because SVG nodes are not created properly within Angular.js.</p>
  
  <p>After poking around further, I found <a href="http://jasonmore.net/angular-js-svg-directives-ng-repeat-templates/" rel="nofollow noreferrer">this solution, which involves using a helper function</a> to replace the relevant DOM elements with properly created SVG nodes, a la:</p>
  
  <pre><code>  .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 &amp;&amp; !attribute.match(/\$/) &amp;&amp; (typeof value !== 'string' || value !== '')) {
              node.setAttribute(attribute, value);
          }
        }
        return node;
    });
  </code></pre>
  
  <p>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.</p>
  
  <p>My question is whether the following would be a reasonable workaround:</p>
  
  <pre><code>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);
          }
        };
      });
  
  });
  </code></pre>
  
  <p>And this works in <a href="http://plnkr.co/edit/34PwAbyoP30I7NRJQYaX?p=info" rel="nofollow noreferrer">Plunker</a>! </p>
  
  <p>Is it valid for me to redefine existing SVG element directives in this way? </p>