Is there some innerHTML replacement in SVG/XML?
Solution 1
You can use DOMParser to parse XML. You can then use importNode to get that into your existing document if you want via importNode to end up with something like this...
var doc = new DOMParser().parseFromString(
'<svg xmlns="http://www.w3.org/2000/svg"><circle cx="100" cy="100" r="20"/></svg>',
'application/xml');
someElement.appendChild(
someElement.ownerDocument.importNode(doc.documentElement, true));
Solution 2
Check out the innerSVG javascript shim, it provides the functionality you want.
2014 update: The DOM parsing spec defines innerHTML
and outerHTML
on Element
, which makes these available on svg and xml elements. This has been shipping in Blink for a while now, first versions to support this was Chrome 32 / Opera 19, more details can be found in this bugreport.
Solution 3
Here I write a dirty way...
innerHTML workaround for SVG
http://jsfiddle.net/microbians/8ztNU/
<html>
<body>
<svg id="svgcanvas">
</svg>
<script>
var twocircles='<circle cx="253" cy="562" r="10" stroke="black" stroke-width="2" fill="red"></circle> \
<circle cx="353" cy="562" r="10" stroke="black" stroke-width="2" fill="red"></circle>'
var receptacle = document.createElement('div');
var svgfragment='<svg>'+twocircles+'</svg>';
receptacle.innerHTML=''+svgfragment;
var Nodes=Array.prototype.slice.call(receptacle.childNodes[0].childNodes);
Nodes.forEach(function(el){document.getElementById('svgcanvas').appendChild(el)})
</script>
</body>
</html>
Enjoy!
Solution 4
The short answer is "No, there is nothing equivalent in the world of XML that lets you hand it a bit of markup and have it automatically create all the elements and attributes in the proper namespaces for the location where you insert it."
The closest direct answer is what @Robert has. As noted in my comments, even then you'll need to create any snippets inside an SVG document that has the same namespaces and prefixes as the document into which you'll be inserting the fragment.
Instead, you might find it is as easy (or easier) to use a convenience method on the standard DOM methods:
// Create a named SVG element on a node, with attributes and optional text
function appendTo(node,name,attrs,text){
var p,ns=appendTo.ns,svg=node,doc=node.ownerDocument;
if (!ns){ // cache namespaces by prefix once
while (svg&&svg.tagName!='svg') svg=svg.parentNode;
ns=appendTo.ns={svg:svg.namespaceURI};
for (var a=svg.attributes,i=a.length;i--;){
if (a[i].namespaceURI) ns[a[i].localName]=a[i].nodeValue;
}
}
var el = doc.createElementNS(ns.svg,name);
for (var attr in attrs){
if (!attrs.hasOwnProperty(attr)) continue;
if (!(p=attr.split(':'))[1]) el.setAttribute(attr,attrs[attr]);
else el.setAttributeNS(ns[p[0]]||null,p[1],attrs[attr]);
}
if (text) el.appendChild(doc.createTextNode(text));
return node.appendChild(el);
}
function clear(node){
while (node.lastChild) node.removeChild(node.lastChild);
}
With this you can do things like:
var icons={
Apps : "/images/apps.png",
Games : "/images/games.png"
}
var wrap = document.querySelector('#container');
clear(wrap);
for (var label in icons){
if (!icons.hasOwnProperty(label)) continue;
var icon = appendTo(wrap,'g',{'class':'icon'});
appendTo(icon,'image',{'xlink:href':icons[label]});
appendTo(icon,'text',{x:10,y:20},label);
}
This is IMHO cleaner than trying to construct the raw SVG markup using string concatenation:
var svg = [];
for (var label in icons){
if (!icons.hasOwnProperty(label)) continue;
svg.push('<g class="icon">');
svg.push('<image xlink:href="'+icons[label]+'" />');
svg.push('<text x="10" y="20">'+label+'</text>');
svg.push('</g>');
}
wrap.innerSVG = svg.join(''); // doesn't work, of course
Solution 5
With jQuery, you can do it this way:
Let's suppose your svgString
contains your svg image after the replacing operations.
$(svgString)[0]
to create a svg tag corresponding to your string. Then you can append this element where you want in the dom to draw the image.
I hope this helps
Sirko
Researcher @ German Aerospace Center (DLR) Insitute of Data Science Group for Data Management and Analysis
Updated on July 09, 2022Comments
-
Sirko almost 2 years
In HTML I can build a simple templating system by providing a template in form of a string, replace some parts of it and then assign it using
innerHTML
to some container.var templ = '<span>{myText}</span>' var newContent = templ.replace( '{myText}', someVariable ); document.querySelector( '#myContainer' ).innerHTML = newContent;
This way I can take advantage of the browser's HTML parser and do not have to repeatedly use
document.createElement()
. The later can be quite cumbersome, if the templates grows beyond a few elements.In SVG, however, there is no property on the elements as
innerHTML
or eveninnerSVG
for that matter.So my question is: Is there anything I can use in SVG ro resemble the approach from the example above or am I stuck with
document.createElement()
(or respectivly some lib that uses it)?As always with my questions: Vanilla JavaScript solutions are preferred, but any pointer to a lib providing a solution is appreciated.
-
Phrogz over 12 yearsAre you certain that this will create elements in the proper namespace?
-
Phrogz over 12 yearsThis requires the fragment to be a valid XML document (single root only), right? And for fragments not parented by an SVG element with the proper namespace, would the created elements have a correct namespace?
-
Phrogz over 12 yearsYou may want/need to wrap this up as a function that wraps the string in an SVG root with all common namespaces and prefixes predefined, and then extract the contents.
-
Robert Longson over 12 yearsYes, the fragment would need a namespace attribute.
-
Sirko about 9 years
innerHTML
has some functionality beyond just setting the text-value of a node, but triggers HTML parsing. So I think I'm not able to add new nodes by usingtextContent
. -
AJFarkas about 9 yearsGood catch. Yeah, I usually use
document.createElement(...)
, but could write a function that handles it. -
nroose about 9 yearsHey, do you know if there is a way to get innerSVG to work with SVG that is in an <object>? Seems like it works only for inline svg, and our stuff currently only works with SVG in an <object>... Thanks.
-
Erik Dahlström about 9 years@nroose yes, it's possible, see xn--dahlstrm-t4a.net/svg/html/…. If you can't get it to work please post a new question.
-
Bharata over 5 yearsIt does not work! I have tested it with IE10 (it is from year 2012) and.current Opera version. Did you ever test it?