Polymer/polymer

template doesn't work inside svg elements

Closed this issue ยท 41 comments

For example:

    <dom-module id="test-element">
      <template>
        <svg class="clock" version="1.1" xmlns="http://www.w3.org/2000/svg">
          <template is="dom-repeat" items="{{positions}}" as="cx">
            <ellipse r="25" cx$="{{cx}}" cy="25" stroke="black"></ellipse> 
          </template>
        </svg>
      </template>
      <script>
        Polymer({
          is: 'test-element',
          ready: function() {
            this.positions = [0, 100, 200, 300];
          },
        });
      </script>
    </dom-module>

This produces the following JS error:

Uncaught TypeError: Cannot read property 'nodeType' of undefined

The problem seems to be that the dom template object doesn't have a content property. This worked fine in Polymer 0.5.

Demo here: http://jsbin.com/wiqowo/31/edit?html,output

It looks like some code didn't make it over from 0.5 that explicitly addressed this issue. Template elements with a <svg> parent have the same namespaceURI (http://www.w3.org/2000/svg), so the browser doesn't implement HTMLTemplateElement. The bootstrap code in 0.5 basically transplanted all child nodes of any svg-namespaced template into a new html-namespaced template, and then inserted that node back in its place.

If anyone else is looking for a workaround, you can put this snippet at the top of your element's <script> tag (it must be evaluated before call to Polymer()). It basically performs the same operation as it was done it 0.5. note: this snippet only works in chrome atm -- not sure yet how to get firefox working

We also hit this issue, thanks for the workaround @bendavis78 .

Will it be fixed in Polymer?

@bendavis78 your snippet was a day saviour for me but it still has some problem. If you have more than one polymer element on the page and this svg element is not the first one the snippet breaks. This line:

var root = doc.querySelector('dom-module > template').content;

should be changed so dom-module becomes the actual #id-of-svg-element which is put in the <dom-module id="id-of-svg-element">

+1

Same error in Chrome 49, even with the tweaked version of svg-template-support.js, and also:
svg-template-support.js:4 Uncaught TypeError: Cannot read property 'content' of null

+1 same error in latest chrome

Thanks for the workaround - would be really nice to have templates within SVG work natively !

Does anyone know of a way to implement the workaround while still vulcanizing elements?

Note that the June 28, 2015 workaround does not work in Firefox 45.0.2 - it will actually prevent any of the svg from being rendered.

Ran into this issue today. Any word on Polymer 1.0 support?

+1 same error

Although there is already a pull-request #3372 that could fix the namespace issue, here would be a work-around, that would build up the svg-node recursivly node by node.

For that there could be a container-element:

<dom-module id="svg-container">
  <template>
    <svg id="svg" version="1.1" xmlns="http://www.w3.org/2000/svg"></svg>
    <content select="svg-component"></content>
  </template>

  <script>
    Polymer({
      is: 'svg-container',

      attached: function() {
        for (var i = 0; i < this.attributes.length; i++) {
          this.$.svg.setAttribute(Polymer.CaseMap.dashToCamelCase(this.attributes[i].name), this.attributes[i].value);
        }
      }
    });
  </script>
</dom-module>

and a element as svg-component, that creates the kind of svg-element, to be attached:

<dom-module id="svg-component">
  <template>
    <content select="svg-component"></content>
  </template>
  <script>
    SvgComponent = Polymer({
      is: 'svg-component',

      _node: {},
      _namespace: 'http://www.w3.org/2000/svg',

      get rootElement () {
        if (this.parentNode.nodeName === 'SVG-CONTAINER')
          return this.parentNode.$.svg;
        else
          return this.parentNode._node;
      },

      factoryImpl: function(attributes) {
        for (var key in attributes)
          this.setAttribute(key, attributes[key]);
      },

      attached: function() {
        var is = this.attributes.is.value;

        if (is !== undefined) {
          this._node = document.createElementNS(this._namespace, is);
          for (var i = 0; i < this.attributes.length; i++) {
            if (this.attributes[i].name !== 'is')
              this._node.setAttribute(this.attributes[i].name, this.attributes[i].value);
          }
          this.rootElement.appendChild(this._node);
        }
      }
    });
  </script>
</dom-module>

Property binding would have to be formally and also event-binding, but you could use that to do it automatically. It would definitely be better, that SVG namespace is implemented in Polymer as an option for registration of new elements .

And in a test: plunker

@fooloomanzii Thanks a lot for the workaround. You saved me a lot of time !

+1 for native implementation.

+1 for native implementation

+1

+1 amazing to see one year later and still an issue

bcopy commented

+1

@kevinpschaaf is this going to be possible in polymer 2 ?

sz332 commented

This is still an issue :(

Provided a workaround for now, tested in FF/Safari/IE, bundled/unbundled.
https://github.com/garryyao/polymer-svg-template

any official workaround here?

+1

axax commented

+1

+1

For people looking for a working solution,
#1976 (comment)

We have a proposal for a core solution:

Detect if a <template> is inside an element that is in a SVG namespace (if it has namespaceURI which is SVG), then swap its contents into an svg element, do the parsing and then swap it back. This should be in parse-template.

The way to handle the transformation, is to expose a function Polymer.svg which transforms a tagged string into the corresponding svg namespace and returns the corrected template.

This whole process ensures that the elements are parsed in the correct namespace, to make sure the actual nodes are created. Then once the parsing has completed, we can swap the correctly constructed nodes back into the template.

We will be working on this issue this week to hopefully finally fix svg compatibility with templates + custom elements.

Above comment has been implemented in #5135. Would be great to get some feedback whether this is actually working for your use-cases ๐ŸŽ‰

Note full fix is blocked on webcomponents/shadycss#166

Is there a way forward with this issue? It seems like there is a Polymer solution (#5135) but it has been held back because of the possibility of addressing the issue at the platform level; however from what I can sense by reading whatwg/html#3553 and whatwg/html#3563 it does not seem that a platform level solution is likely any time soon.

Update: It seems that this is solved in the new lit-html templating system (https://lit-html.polymer-project.org/guide), which is at release candidate stage (as of 17 December 2018).

stale commented

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale commented

This issue has been automatically closed after being marked stale. If you're still facing this problem with the above solution, please comment and we'll reopen!