AngularJS ng-href and svg xlink
Solution 1
You can use ng-attr-<some attribute>
ng-attr-xlink:href="{{xxx}}"
works for me.
Note that you also need an empty xlink:href=""
as initial value. – Derek Hsu
Solution 2
If, like me, you're looking for a way to add images to svg, you can do so adding:
xlink:href="" ng-href="{{ foo }}"
Example:
http://jsbin.com/sigoleya/1/edit?html,js,output
Where I found the solution:
https://github.com/angular/angular.js/issues/7697
Solution 3
I ran into a similar problem when trying to output a value for xlink:href
that's tied to the model. Based on the user's chosen <option>
in a <select>
control, I was trying to show a dynamic SVG icon via the xlink:href
attribute of the <use>
element.
I found a thread about this in the GitHub Issues for AngularJS. Based on the discussion there, it appears that because a viable workaround exists, they've effectively tabled a fix by moving it to the Backlog milestone.
What ultimately worked for me was inspired by this JSBin:
http://jsbin.com/sigoleya/1/edit?html,js,output
Here's the code I used in my template:
<svg class="icon" data-ng-class="category.iconName">
<use xlink:href="" data-ng-href="{{'#' + category.iconName}}">
</svg>
Given a category.iconName
of icon-music
, for example, Angular sets the xlink:href
dynamically to #icon-music
, which references the <svg id="icon-music">
element further up on the same page.
As others have noted, what's key is setting a blank xlink:href=""
attribute on the element where you call the ngHref
directive. Attribute order does not seem to matter. Using ng-attr-xlink:href="{{xxx}}"
(as mentioned in Derek Hsu's answer) did not work for me.
All of this assumes Angular 1.3.36.
Solution 4
I solved the same problem with the following modules:
Module for SVGs:
var app = angular.module('Svgs', []);
angular.forEach([
{ ngAttrName: 'ngXlinkHref', attrName: 'xlink:href' },
{ ngAttrName: 'ngWidth', attrName: 'width' },
{ ngAttrName: 'ngHeight', attrName: 'height' }
], function (pair) {
var ngAttrName = pair.ngAttrName;
var attrName = pair.attrName;
app.directive(ngAttrName, function (IeHelperSrv) {
return {
priority: 99,
link: function (scope, element, attrs) {
attrs.$observe(ngAttrName, function (value) {
if (!value) return;
attrs.$set(attrName, value);
if (IeHelperSrv.isIE) element.prop(attrName, value);
});
}
};
});
});
Module for IE detection:
angular.module('IeHelper', []).factory('IeHelperSrv', function () {
return {
isIE: checkForIE.isIE,
}
});
var checkForIE = {
init: function () {
this.isIE = (navigator.userAgent.indexOf('MSIE') != -1);
}
};
checkForIE.init();
HTML:
<!-- image has initial fake source, width and height to force it to render -->
<image xlink:href="~/Content/Empty.png" width="1" height="1"
ng-xlink-href="{{item.imageSrc}}"
ng-width="{{item.width}}" ng-height="{{item.height}}"
ng-cloak
/>
Solution 5
For anyone else having this problem due to Angular/Angular UI Router in HTML5 mode, I came up with a straightforward fix to enable svg sprite icons to work with their xlink:href attribute and the tag.
Gist is here: https://gist.github.com/planetflash/4d9d66e924aae95f7618c03f2aabd4a3
app.run(['$rootScope', '$window', function($rootScope, $window){
$rootScope.$on('$locationChangeSuccess', function(event){
$rootScope.absurl = $window.location.href;
});
<svg><use xlink:href="{{absurl+'#svgvID'}}"></use></svg>
Leon Radley
I am the CTO at wec360.com. Scandinavias leading visualization platform.
Updated on June 06, 2022Comments
-
Leon Radley about 2 years
I'd like some input on using xml namespaced attributes with angular.
The problem is angular comes with a couple of directives to handle writing attributes such as href and src when angular has parsed the expresssions (otherwise the browser will try to load
{{mymodel.myimage}}
as a url)https://github.com/angular/angular.js/blob/master/src/ng/directive/booleanAttrs.js#L329
The problem I'm facing is that I'm using angular to output svg together with D3 and since angular doesn't have a way to output
xlink:href
I was stuck.I created a custom directive that outputs xlink:href
app.directive('ngXlinkHref', function () { return { priority: 99, restrict: 'A', link: function (scope, element, attr) { var attrName = 'xlink:href'; attr.$observe('ngXlinkHref', function (value) { if (!value) return; attr.$set(attrName, value); }); } }; });
Full demo: http://plnkr.co/edit/cMhGRh
But it seems that if I don't manually add xlink:href to the element, the svg image will not render.
Any suggestions on how to best handle xml namespaces / svg together with angular would be greatly appreciated.
-
coblr over 10 yearsWhen the xlink:href wasn't working for me, I had to re-read this post. The key here is that YOU NEED A FAKE VALUE TO START WITH. Without it, the image will not render even with the correct attribute. Leaving this comment to help other TL;DR dummies like me. Thanks Danny!
-
Reaper over 10 years@fractalspawn You are welcome. I was going to add this comment to the answer, then I saw I already put this in a comment above the HTML :-)
-
Siddharth almost 10 yearsThis does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post - you can always comment on your own posts, and once you have sufficient reputation you will be able to comment on any post.
-
Derek Hsu almost 10 years@Siddharth, Actually it does. The question is not simply about custom directives. Indeed, @Leon wanted some input on using xml namespaced attributes with angular and suggestions on how to best handle xml namespaces / svg together with angular. To resolve his problem, he was even writing custom directives. I am pointing out that custom directives are not necessary. Angularjs already has
ng-attr
which does the job for him. -
sheriffderek almost 10 yearsHow about a fiddle to prove this? It's not working for me...
<svg><use ng-attr-xlink:href="#icon-{{notification.type}}"></use></svg>
-
Derek Hsu almost 10 years@sheriffderek, here you go angularjs ng-attr example. Note that you also need an empty
xlink:href=""
as initial value. -
sheriffderek almost 10 yearsI was hoping to use it with <use> -- so that I can target pieces of a sprite. I don't really have any reason to put an image in an svg.
-
sheriffderek almost 10 yearsAH --- actually --- I didn't read it properly. Here is a codepen where I have it working the way I want. Why don't you put the actual directive code in the answer? Then it would be correct. : ) - codepen.io/sheriffderek/pen/EdCDr THANKS!
-
eCommerce Guru almost 10 years+1, This works for me, but it's VERY picky. You meed the empty xlink:href="" AFTER the dynamic ng-attr-xlink:href. Also, I don't think this works for earlier versions of Angular.
-
Mattijs over 7 yearsthis is pretty brilliant. Thanks!
-
Mohamed Hussain about 5 yearsthank u so much it works for me...ng-attr-xlink:href="{{model}}" didnt work for me.....
-
Nitsan Baleli over 4 yearscoffeescript: <use xlink:href="" ng-attr-href="\#{{$ctrl.name}}"></use>