Reputation: 1730
All tutorials with adding svg to a component in AngularCli that I found recommend to insert it in html template, something like this:
<div>
<svg viewBox="0 0 250 250">
<svg:g class="group">
<svg:polygon class="shield" points="125,30 125,30 125,30 31.9,63.2 46.1,186.3 125,230 125,230 125,230 203.9,186.3 218.1,63.2" />
<svg:path class="a" d="M125,52.1L66.8,182.6h0h21.7h0l11.7-29.2h49.4l11.7,29.2h0h21.7h0L125,52.1L125,52.1L125,52.1L125,52.1
L125,52.1z M142,135.4H108l17-40.9L142,135.4z"/>
</svg:g>
</svg>
</div>
But I wish to keep templates clear and instert only few tags in it with url to separated svg file, somwehow like this:
<svg class="star">
<use xlink:href="../../../assets/images/svg/star.svg"
x="0"
y="0" />
</svg>
Ho do I use separated svg files in components?
Upvotes: 43
Views: 123850
Reputation: 1
Coudn't make it work with any solution. Finally came up with this:
import { CommonModule } from '@angular/common';
import { HttpClient } from '@angular/common/http';
import { Component, ElementRef, Input, OnInit } from '@angular/core';
@Component({
selector: 'app-svg-icon',
standalone: true,
imports: [CommonModule],
template: `<div class="svg-container" [ngClass]="this.class"></div>`
})
export class SvgIconComponent implements OnInit {
@Input() icon: string = '';
@Input() class: string = '';
constructor(
private http: HttpClient,
private el: ElementRef
) {}
ngOnInit(): void {
this.loadSvg();
}
loadSvg(): void {
if (this.icon) {
this.http.get(`assets/icons/${this.icon}.svg`, { responseType: 'text' }).subscribe(
svgContent => {
this.insertSvgContent(svgContent);
},
error => {
console.error('Error loading SVG:', error);
}
);
}
}
insertSvgContent(svgContent: string): void {
const svgContainer = this.el.nativeElement.querySelector('.svg-container');
svgContainer.innerHTML = svgContent; // Inject SVG content into the container
const svgElement = svgContainer.querySelector('svg');
if (svgElement) {
svgElement.classList.add('loaded-svg'); // Add a class for styling purposes
}
}
}
And use it like:
<app-svg-icon class="h-4 w-4 text-red-700" icon="trash-bin"></app-svg-icon>
In this case i'm using tailwind to style my svg's
Upvotes: 0
Reputation: 92377
You can do it directly by use SVG instead HTML as component template - more details here.
Working example here
@Component({
selector: 'app-my-svg',
templateUrl: './my-svg.component.svg',
styleUrls: ['./my-svg.component.css']
})
export class MySvgComponent {
...
inside this SVG template (which is in separate file!) you can use styles and variables in angular way
Upvotes: 4
Reputation: 1482
2024 version. The icon was not visible until I set the innerHtml programatically. Also beware of auth interceptors, adding headers to the get request can cause it to fail with empty error.
import { HttpClient } from '@angular/common/http';
import { ChangeDetectionStrategy, Component, ElementRef, HostBinding, Input, OnChanges, ViewChild, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'app-icon',
template: `<span #svgContainer></span>`,
changeDetection: ChangeDetectionStrategy.OnPush,
encapsulation: ViewEncapsulation.None,
})
export class IconComponent implements OnChanges {
@Input() src?: string;
@ViewChild('svgContainer', { static: true }) svgContainerRef!: ElementRef;
@HostBinding('style.display') display = 'inline-flex';
constructor(private http: HttpClient) { }
ngOnChanges() {
if (!this.src) return;
this.http.get(this.src, { responseType: 'text' }).subscribe((data) => {
const div = this.svgContainerRef.nativeElement;
if (div) {
div.innerHTML = data;
}
});
}
}
This component is then being used like this:
<app-icon [src]="icons.logout"></app-icon>
where icons are simple urls like this:
export const icons = {
arrowRightO: 'assets/icons/arrow-right-o.svg',
home: 'assets/icons/home-alt.svg',
upload: 'assets/icons/software-upload.svg',
logout: 'assets/icons/log-out.svg',
}
Upvotes: 0
Reputation: 47
Angular - create one more component, add a lot of stuff, etc and then get your svg.
React - just make an import of your svg and continue to work.
(and yes, it will be added as tag. You can fill it with css, change it whatever you like)
Compare React and Angular imort of SVG
Upvotes: 0
Reputation: 1819
HttpClient
to fetch for the file, then use bypassSecurityTrustHtml
to render it with [innerHTML]
.This may be a bit late for an answer, but here's how we found the solution. we tried looking up into how angular material does it for their icons, and boy were we surprised to how simple it really is. They were just fetching the file using HttpClient
! It was already at the back of our minds but we kept ignoring it cause we thought maybe there was a better solution.
So after a few minutes of searching, we stumbled upon this: https://github.com/angular/components/blob/653457eaf48faab99227f37bc2fe104d9f308787/src/material/icon/icon-registry.ts#L621
So basically, if you have your SVG file somewhere in your assets folder (/assets/images/svg/star.svg
), all you have to do is to fetch it using HttpClient.get
and use the DomSanitizer
to bypass security and trust the given value to be safe HTML before you can render it to your component.
And finally, here's how our component looks like:
import { Component, OnChanges, SecurityContext } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { DomSanitizer } from '@angular/platform-browser';
@Component({
selector: 'app-svg-icon',
template: `<span [innerHTML]="svgIcon"></span>`,
styleUrls: ['./svg-icon.component.scss'],
})
export class SvgIconComponent implements OnChanges {
@Input()
public name?: string;
public svgIcon: any;
constructor(
private httpClient: HttpClient,
private sanitizer: DomSanitizer,
) {
}
public ngOnChanges(): void {
if (!this.name) {
this.svgIcon = '';
return;
}
this.httpClient
.get(`assets/images/svg/${this.name}.svg`, { responseType: 'text' })
.subscribe(value => {
this.svgIcon = this.sanitizer.bypassSecurityTrustHtml(value);
});
}
}
Now you can just import the component anywhere in your app as
<app-svg-icon name="star"></app-svg-icon>
Upvotes: 23
Reputation: 155
There is a more elegant way, however it implies that the svg file has the same ID as the file name.
Svg component:
import { Component, Input, OnInit } from '@angular/core';
@Component({
selector: 'app-svg-icon',
template: '
<svg attr.width="{{width}}px" attr.height="{{height}}px" attr.fill="{{fill}}" attr.class="{{class}}">
<use attr.xlink:href="assets/icons/{{icon}}.svg#{{icon}}"></use>
</svg>
',
})
export class SvgIconComponent implements OnInit {
@Input() icon!: string;
@Input() width?: number;
@Input() height?: number;
@Input() size?: number = 24;
@Input() fill?: string;
@Input() class?: string;
ngOnInit(): void {
if (!this.width || !this.height) {
this.width = this.size;
this.height = this.size;
}
}
}
Let's say you have svg in a folder: /assets/icons/person.svg
The svg itself contains the following code (So that you can easily change the size and color of your svg, it should not contain height, width and fill attributes):
<svg id="person" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M12 5.9c1.16 0 2.1.94 2.1 2.1s-.94 2.1-2.1 2.1S9.9 9.16 9.9 8s.94-2.1 2.1-2.1m0 9c2.97 0 6.1 1.46 6.1 2.1v1.1H5.9V17c0-.64 3.13-2.1 6.1-2.1M12 4C9.79 4 8 5.79 8 8s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 9c-2.67 0-8 1.34-8 4v3h16v-3c0-2.66-5.33-4-8-4z" />
</svg>
And now you can use your icon in any component:
<app-svg-icon [icon]="'person'" fill="red" [size]="48"></app-svg-icon>
Upvotes: 3
Reputation: 649
So I was trying to do this, and for the life of me i could not get this svg to show up until.... After many internet searches, and I don't think it's just me and if you copy pasta path from the internet then maybe you forgot to include this
xmlns="http://www.w3.org/2000/svg"
<svg xmlns="http://www.w3.org/2000/svg" height="100" width="100">
<path d="I love copying and pasting paths"/>
</svg>
Then you can go ahead and do your
<img src="assets/img/logo.svg" />
and if this doesn't work and somehow you want to work with images instead then put your images in
assets/img/copypasta.png
Upvotes: 1
Reputation: 568
one way to do this is to set id property for your svg file and put your svg files in your asset folder. then use that id in mat-icon like this:
<mat-icon svgIcon="my-star-icon"></mat-icon>
this is a better way to do it; in this way you don't have to deal with svg tags in your UI html code. also this supports google icons.
though this works if you're using angular material.
Edit: You need to register the icon with the IconRegistry in your component for this to work:
constructor(iconRegistry: MatIconRegistry, sanitizer: DomSanitizer) {
iconRegistry.addSvgIcon(
'my-star-icon',
sanitizer.bypassSecurityTrustResourceUrl('assets/icons/my-star-icon.svg'));
}
Check the docs here and an example here.
Upvotes: 7
Reputation: 4453
If you have logo.svg
:
src/assets
folderangular.json
config: "assets": [ "src/assets" ]
<img src="assets/svg/logo.svg">
Upvotes: 48
Reputation: 627
Include your SVG files in src/assets folder and add the svg folder in your angular.json
file.
"assets": [ "src/assets/svg/*" ]
This way you can include the file in your components as you wish.
Upvotes: 19