4

My goal is to convert code from Angular 1.3 to Angular 2 (with SVG in both cases).

I tried the following simple test code, which works in case #1 that does not involve interpolation, but does not work in case #2 (which uses interpolation), and AFAICS the only difference in the generated SVG code is the inclusion of an extra attribute in the element: class="ng-binding"

Is there a way to suppress the preceding class attribute, or is there another solution?

Btw I wasn't able to get the formatting quite right (my apologies).

Contents of HTML Web page:

<html> 
  <head>
    <title>SVG and Angular2</title>
    <script src="quickstart/dist/es6-shim.js"></script>
  </head>

  <body> 
    <!-- The app component created in svg1.es6 --> 
    <my-svg></my-svg>

    <script>
      // Rewrite the paths to load the files
      System.paths = {
        'angular2/*':'/quickstart/angular2/*.js', // Angular
        'rtts_assert/*': '/quickstart/rtts_assert/*.js', // Runtime assertions
        'svg': 'svg1.es6' // The my-svg component
      };

      System.import('svg');
    </script>    
  </body>
</html>

Contents of the JS file:

import {Component, Template, bootstrap} from 'angular2/angular2';

@Component({
  selector: 'my-svg'
})

    @Template({
    //case 1 works:
      inline: '<svg>&lt;ellipse cx="100" cy="100" rx="80" ry="50" fill="red"&gt;&lt;/ellipse&gt;</svg>'


//case 2 does not work:
//inline: "<svg>{{graphics}}</svg>"
})    

class MyAppComponent {
  constructor() {
    this.graphics = this.getGraphics(); 
  }   

  getGraphics() { 
     // return an array of SVG elements (eventually...)
     var ell1 = 
        '<ellipse cx="100" cy="100" rx="80" ry="50" fill="red"></ellipse>';
     return ell1;
  } 
}

bootstrap(MyAppComponent);
Paul LeBeau
  • 97,474
  • 9
  • 154
  • 181
Oswald Campesato
  • 183
  • 1
  • 2
  • 8

2 Answers2

3

SVG elements do not use the same namespace as HTML elements. When you insert SVG elements into the DOM, they need to be inserted with the correct SVG namespace.

Case 1 works because you are inserting the whole SVG, including the <svg> tags, into the HTML. The browser will automatically use the right namespace because it sees the <svg> tag and knows what to do.

Case 2 doesn't work because you are just inserting an <ellipse> tag and the browser doesn't realise it is supposed be created with the svg namespace.

If you inspect both SVGs with the browser's DOM inspector, and look at the <ellipse> tag's namespace property, you should see the difference.

Paul LeBeau
  • 97,474
  • 9
  • 154
  • 181
  • If you can't insert the whole SVG, then you will need to create the elements yourself using `document.createElementNS()` etc. – Paul LeBeau May 01 '16 at 01:45
2

You can use outerHtml of an HTML element like:

@Component({
  selector: 'my-app',
  template: `
    <!--
      <svg xmlns='http://www.w3.org/2000/svg'><ellipse cx="100" cy="100" rx="80" ry="50" fill="red"></ellipse></svg>
    --> 

    <span [outerHTML]="graphics"></span>`
})
export class App {
  constructor() {
    this.graphics = this.getGraphics();
  }

  getGraphics() {
     // return an array of SVG elements (eventually...)
     var ell1 =
        '<svg><ellipse cx="100" cy="100" rx="80" ry="50" fill="red"></ellipse></svg>';
     return ell1;
  }
}

note that the added string has to contain the <svg>...</svg>

See also How can I add a SVG graphic dynamically using javascript or jquery?

Community
  • 1
  • 1
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567