Alpine version: 2.4.1
I'm getting an error when using x-for on a template tag to generate SVG elements. With the following HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Rectangle Editor</title>
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/alpine.js"></script>
</head>
<body>
<div x-data="rectangleEditor()">
<svg width="1024" height="1024">
<!-- Error -->
<template x-for="rectangle in rectangles" :key="rectangle">
<rect :x="rectangle.x" :y="rectangle.y" :width="rectangle.width" :height="rectangle.height" />
</template>
</svg>
<!-- No error -->
<template x-for="rectangle in rectangles" :key="rectangle">
<div :x="rectangle.x" :y="rectangle.y" :width="rectangle.width" :height="rectangle.height" />
</template>
</div>
<script>
function rectangleEditor() {
return {
rectangles: [
{ x: 20, y: 40, width: 200, height: 400 },
{ x: 60, y: 100, width: 500, height: 500 },
{ x: 200, y: 40, width: 100, height: 400 },
{ x: 300, y: 40, width: 100, height: 400 },
],
}
};
</script>
</body>
</html>
I don't get such an error when using x-for outside a svg element. But as soon as I add elements in a svg element using x-for (even standard HTML elements such as div), I get the following stack trace:
Chromium 81:
alpine.js:76 Uncaught TypeError: Cannot read property 'childElementCount' of undefined
at warnIfMalformedTemplate (alpine.js:76)
at handleForDirective (alpine.js:438)
at alpine.js:1570
at Array.forEach (<anonymous>)
at Component.resolveBoundAttributes (alpine.js:1530)
at Component.initializeElement (alpine.js:1446)
at alpine.js:1430
at alpine.js:1420
at walk (alpine.js:84)
at walk (alpine.js:88)
Firefox 78:
Uncaught TypeError: el.content is undefined
alpinejs 2.4.1/dist/alpine.js:76
alpinejs 2.4.1/dist/alpine.js:438
alpinejs 2.4.1/dist/alpine.js:1570
alpinejs 2.4.1/dist/alpine.js:1530
alpinejs 2.4.1/dist/alpine.js:1446
alpinejs 2.4.1/dist/alpine.js:1430
alpinejs 2.4.1/dist/alpine.js:1420
alpinejs 2.4.1/dist/alpine.js:84
alpinejs 2.4.1/dist/alpine.js:88
alpinejs 2.4.1/dist/alpine.js:88
alpinejs 2.4.1/dist/alpine.js:1408
alpinejs 2.4.1/dist/alpine.js:1425
alpinejs 2.4.1/dist/alpine.js:1355
alpinejs 2.4.1/dist/alpine.js:1735
alpinejs 2.4.1/dist/alpine.js:1678
alpinejs 2.4.1/dist/alpine.js:1694
alpinejs 2.4.1/dist/alpine.js:1693
alpinejs 2.4.1/dist/alpine.js:1677
If this isn't supported, then this should be documented in the README. (I'm willing to open a PR for that if this is the case.)
FWIW I suspect this is not an Alpine issue - if you are using HTML tags (like template) inside an SVG element they will have an SVG namespace so HTML elements like HTMLTemplateElement won't be implemented by the browser. I ran into something similar a while back trying to use vanilla JS and templates in SVG elements.
Edit: Sounds like Polymer ran into something similar and there is now a WHATWG feature request open to provide support: https://github.com/whatwg/html/issues/3563 - not much help in the short term though.
Yeah, it's a DOM issue. templates inside an svg tag are not implemented and they miss the content property (you can see it using the inspector without alpine).
You need to include a polyfil like the one below (adapted from one mentioned on the polymer issue)
(function(){
var templates = document.querySelectorAll('svg template');
var el, template, attribs, attrib, count, child, content;
for (var i=0; i<templates.length; i++) {
el = templates[i];
template = el.ownerDocument.createElement('template');
el.parentNode.insertBefore(template, el);
attribs = el.attributes;
count = attribs.length;
while (count-- > 0) {
attrib = attribs[count];
template.setAttribute(attrib.name, attrib.value);
el.removeAttribute(attrib.name);
}
el.parentNode.removeChild(el);
content = template.content;
while ((child = el.firstChild)) {
content.appendChild(child);
}
}
})();
@SimoTod That polyfill seems to be working (tested in Firefox and Chromium). Thanks a lot :slightly_smiling_face:
No worries. Make sure you test it on all browsers you support (IE11, old edge, Safari, etc). It should work but I did not check. 馃憤
Most helpful comment
Yeah, it's a DOM issue. templates inside an svg tag are not implemented and they miss the content property (you can see it using the inspector without alpine).
You need to include a polyfil like the one below (adapted from one mentioned on the polymer issue)