html5 - angular ng-href y svg xlink
angularjs angularjs-directive (7)
Esto me llevó más tiempo de lo que hubiera deseado. Alrededor de 20-30 minutos.
Si entiendo correctamente, cualquier carga fallida en el elemento de la imagen dejará inútil ese elemento en el futuro . Creo que es algo similar @GeekyMonkey está diciendo. Si el sistema de enlace angular ha establecido xlink: href inicialmente en nulo, el elemento Image ya no funcionará, incluso si tenemos un valor válido en el futuro.
Aquí hay una solución, observe cómo he envuelto el elemento de imagen dentro del elemento g, usando la directiva ng-if. Eso asegura que nos uniremos a la imagen solo cuando haya un valor correcto disponible.
<g ng-if="vm.svgMap.background != null">
<image
ng-attr-xlink:href="{{vm.svgMap.background.image | trusted}}"
ng-attr-width="{{vm.svgMap.background.width}}"
ng-attr-height="{{vm.svgMap.background.width}}"
xlink:href=""
width="1"
height="1"
x="0"
y="0"></image>
</g>
Como otros dijeron, el orden de los atributos también es importante. Para asegurarnos de que angularJS nos permite unir elemento de imagen, también tendremos que confiar en ese recurso, lo he hecho a través de filtro (es el que está en el atributo xlink: href):
(function() {
''use strict'';
angular.module(''myTool'').filter(''trusted'', TrustedFilter);
function TrustedFilter($sce) {
return function(url) {
return $sce.trustAsResourceUrl(url);
};
};
}());
Me gustaría obtener información sobre el uso de atributos espaciales nombrados xml con angular.
El problema es que angular viene con un par de directivas para manejar atributos de escritura como href y src cuando angular ha analizado las expresiones (de lo contrario, el navegador intentará cargar {{mymodel.myimage}}
como una url)
https://github.com/angular/angular.js/blob/master/src/ng/directive/booleanAttrs.js#L329
El problema al que me enfrento es que estoy usando angulo a salida svg junto con D3 y dado que angular no tiene una forma de enviar xlink:href
estaba atascado.
Creé una directiva personalizada que da salida a 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);
});
}
};
});
Demostración completa: http://plnkr.co/edit/cMhGRh
Pero parece que si no agrego manualmente xlink: href al elemento, la imagen svg no se procesará.
Cualquier sugerencia sobre cómo manejar mejor espacios de nombres xml / svg junto con angular sería muy apreciada.
Me encontré con este problema donde estaba usando Ajax para cargar la hoja de sprites svg en la página. Si tuviera una en la página antes de cargar la hoja de sprites, fallaría y no se resolvería una vez que la hoja de sprites estuviese disponible. Cualquier agregado al dom después de que se cargó la hoja de sprites estaba bien. Tuve que retrasar poner los artículos en el dom hasta que la hoja de sprites terminó de cargarse.
Esto solo afectó a IOS. El resto de navegadores no se preocuparon por el orden.
Me encontré con un problema similar cuando trato de generar un valor para xlink:href
que está vinculado al modelo. En función de la <option>
elegida por el usuario en un control <select>
, estaba tratando de mostrar un icono de SVG dinámico a través del atributo xlink:href
del elemento <use>
.
Encontré https://github.com/angular/angular.js/issues/7697 en los Issues de GitHub para AngularJS. En función de la discusión allí, parece que, debido a que existe una solución alternativa viable, efectivamente han presentado una solución al moverla al hito de Backlog.
Lo que finalmente funcionó para mí fue inspirado por este JSBin:
http://jsbin.com/sigoleya/1/edit?html,js,output
Aquí está el código que utilicé en mi plantilla:
<svg class="icon" data-ng-class="category.iconName">
<use xlink:href="" data-ng-href="{{''#'' + category.iconName}}">
</svg>
Dado un category.iconName
de icon-music
, por ejemplo, Angular establece xlink:href
dinámicamente en #icon-music
, que hace referencia al elemento <svg id="icon-music">
más arriba en la misma página.
Como otros han notado, cuál es la clave es establecer un atributo xlink:href=""
en blanco en el elemento al que llama la directiva ngHref
. La orden del atributo no parece importar. Usar ng-attr-xlink:href="{{xxx}}"
(como se menciona en la respuesta de Derek Hsu) no funcionó para mí.
Todo esto asume Angular 1.3.36.
Para cualquier otra persona que tenga este problema debido al enrutador UI angular / angular en el modo HTML5, se me ocurrió una solución directa para permitir que los iconos svg sprite trabajen con su atributo xlink: href y la etiqueta.
Gist está aquí: 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>
Puede usar ng-attr-<some attribute>
ng-attr-xlink:href="{{xxx}}"
funciona para mí.
Tenga en cuenta que también necesita un xlink:href=""
vacío xlink:href=""
como valor inicial. - Derek Hsu
Resolví el mismo problema con los siguientes módulos:
Módulo para SVG:
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);
});
}
};
});
});
Módulo para detección de IE:
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
/>
Si, como yo, está buscando una forma de agregar imágenes a svg, puede hacerlo agregando:
xlink:href="" ng-href="{{ foo }}"
Ejemplo:
http://jsbin.com/sigoleya/1/edit?html,js,output
Donde encontré la solución: