In an svg, if I use knockout to set the xlink:href
attribute for an a
node, the attribute's namespace isn't set correctly, so the a
doesn't work as a link when clicked.
For example, consider the following svg that contains two linked ellipses. One has its xlink:href
attribute hardcoded, the other is set by knockout via the data-bind
attribute:
<svg width="5cm" height="6cm" viewBox="0 0 5 6" version="1.1"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect x=".01" y=".01" width="4.98" height="5.98"
fill="none" stroke="blue" stroke-width=".03"/>
<a xlink:href="#hardcoded">
<ellipse data-bind="attr: blue" />
</a>
<a data-bind="attr: { 'xlink:href': href }">
<ellipse data-bind="attr: red" />
</a>
</svg>
Getting knockout to run is pretty easy:
ko.applyBindings( {
blue: { cx:2.5, cy:1.5, rx:2, ry:1, fill:"blue" },
href: '#foo',
red: { cx:2.5, cy:4.5, rx:2, ry:1, fill:"red" },
});
But only the link for the hardcoded one works. If I add some code to view the namespaceURI
value for the attribute node, I can see that
the xlink:href
attribute set by knockout has a null
namespaceURI, as opposed to the hardcoded one, which is set to http://www.w3.org/1999/xlink
.
Array.forEach( document.getElementsByTagName('a'), function(a){
a.setAttribute('title', 'xlink:href namespaceURI = ' + a.getAttributeNode('xlink:href').namespaceURI);
});
You can view all this in a fiddle.
Is there an easy way to tell knockout what the correct namespace should be for an attribute, or do I need to write a custom binding?
My fallback solution is to add this custom binding:
and change the template to use the
attr-ns
binding I defined:This seems to work ok, but I'd rather not do this if I don't have to. More custom code = more that could go wrong.
You can view this solution in a fiddle.
You'd have to override the default
attr
binding handler with a namespace-aware version.FWIW, here is my take on it, use it as a transparent drop-in, it even supports namespace prefixes:
http://jsfiddle.net/ZghP7/1/