Angular2 SVG xlink:href

Solution 1:

SVG elements doen't have properties, therefore attribute binding is required most of the time (see also Properties and Attributes in HTML).

For attribute binding you need

<use [attr.xlink:href]="iconHref">

or

<use attr.xlink:href="{{iconHref}}">

Update

Sanitization might cause issues.

See also

  • https://github.com/angular/angular/issues/9510)
  • https://angular.io/docs/ts/latest/api/platform-browser/index/DomSanitizationService-class.html

Update DomSanitizationService is going to be renamed to DomSanitizer in RC.6

Update this should be fixed

but there is an open issue to support this for namespaced attributes https://github.com/angular/angular/pull/6363/files

As work-around add an additional

xlink:href=""

Angular can update the attribute but has issues with adding.

If xlink:href is actually a property then your syntax should work after the PR was added as well.

Solution 2:

I was still having issues with the attr.xlink:href described by Gunter so I created a directive that is similar to SVG 4 Everybody but is specific for angular2.

Usage

<div [useLoader]="'icons/icons.svg#menu-dashboard'"></div>

Explanation

This directive will

  1. Load icons/icons.svg over http
  2. Parse the response and extract path info for #menu-dashboard
  3. Add the parsed svg icon to the html

Code

import { Directive, Input, ElementRef, OnChanges } from '@angular/core';
import { Http } from '@angular/http';

// Extract necessary symbol information
// Return text of specified svg
const extractSymbol = (svg, name) => {
    return svg.split('<symbol')
    .filter((def: string) => def.includes(name))
    .map((def) => def.split('</symbol>')[0])
    .map((def) => '<svg ' + def + '</svg>')
}

@Directive({
    selector: '[useLoader]'
})
export class UseLoaderDirective implements OnChanges {

    @Input() useLoader: string;

    constructor (
        private element: ElementRef,
        private http: Http
    ) {}

    ngOnChanges (values) {
        if (
            values.useLoader.currentValue &&
            values.useLoader.currentValue.includes('#')
        ) {
            // The resource url of the svg
            const src  = values.useLoader.currentValue.split('#')[0];
            // The id of the symbol definition
            const name = values.useLoader.currentValue.split('#')[1];

            // Load the src
            // Extract interested svg
            // Add svg to the element
            this.http.get(src)
            .map(res => res.text())
            .map(svg => extractSymbol(svg, name))
            .toPromise()
            .then(svg => this.element.nativeElement.innerHTML = svg)
            .catch(err => console.log(err))
        }
    }
}