• Что бы вступить в ряды "Принятый кодер" Вам нужно:
    Написать 10 полезных сообщений или тем и Получить 10 симпатий.
    Для того кто не хочет терять время,может пожертвовать средства для поддержки сервеса, и вступить в ряды VIP на месяц, дополнительная информация в лс.

  • Пользаватели которые будут спамить, уходят в бан без предупреждения. Спам сообщения определяется администрацией и модератором.

  • Гость, Что бы Вы хотели увидеть на нашем Форуме? Изложить свои идеи и пожелания по улучшению форума Вы можете поделиться с нами здесь. ----> Перейдите сюда
  • Все пользователи не прошедшие проверку электронной почты будут заблокированы. Все вопросы с разблокировкой обращайтесь по адресу электронной почте : info@guardianelinks.com . Не пришло сообщение о проверке или о сбросе также сообщите нам.

Centralizing SVG Handling in Angular Applications

Sascha Оффлайн

Sascha

Заместитель Администратора
Команда форума
Администратор
Регистрация
9 Май 2015
Сообщения
1,549
Баллы
155


SVG icons are essential for modern web UIs, but managing them directly in templates becomes challenging as applications grow. This post demonstrates how we implemented a scalable approach to SVG management in DevsWhoRun Angular application using modern directives and TypeScript.

The Problem


Inline SVGs in templates lead to several issues:


<button><svg class="w-5 h-5" viewBox="0 0 24 24" xmlns="

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438..." fill="currentColor"></path></svg>
Sign in with GitHub
</button>



  • Template Bloat: SVG markup clutters templates
  • Duplication: Same SVGs repeated across components
  • Inconsistency: Inconsistent rendering
  • Maintenance: Updates require changes in multiple files
The Solution: A Centralized SVG Approach


Our solution consists of two key components:

  1. A TypeScript constants file for SVG definitions
  2. An Angular directive for dynamic SVG rendering
Step 1: Create the SVG Constants File


// svg-icon-constants.ts
import { Icon } from "./types";

// Type-safe icon name constants
export const ICON_NAME = {
google: 'google',
github: 'github',
sun: 'sun',
moon: 'moon',
smile: 'smile',
discord: 'discord'
}

// SVG path data mapped to icon names
export const SVG_ICONS: { [key: Icon]: string } = {
[ICON_NAME.google]: `<svg viewBox="0 0 24 24" xmlns="

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

">
<path d="M12.48 10.92v3.28h7.84c-.24 1.84-.853 3.187-1.787 4.133-1.147 1.147-2.933 2.4-6.053 2.4-4.827 0-8.6-3.893-8.6-8.72s3.773-8.72 8.6-8.72c2.6 0 4.507 1.027 5.907 2.347l2.307-2.307C18.747 1.44 16.133 0 12.48 0 5.867 0 .307 5.387.307 12s5.56 12 12.173 12c3.573 0 6.267-1.173 8.373-3.36 2.16-2.16 2.84-5.213 2.84-7.667 0-.76-.053-1.467-.173-2.053H12.48z"></path>
</svg>`,

[ICON_NAME.github]: `<svg viewBox="0 0 24 24" xmlns="

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

">
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" fill="currentColor"></path>
</svg>`
// Additional icons omitted for brevity
};



Step 2: Create the SVG Icon Directive


// svg-icon.ts
import { Directive, ElementRef, inject, input, OnInit, Renderer2 } from '@angular/core';
import { SVG_ICONS } from './svg-icon-constants';
import { Icon } from './types';

@Directive({
selector: '[appSvgIcon]',
})
export class SvgIcon implements OnInit {
// Modern Angular signals-based inputs
iconName = input<Icon>('google');
iconClass = input<string>('');
fill = input<string>('currentColor');

// Dependency injection using inject function
private readonly el = inject(ElementRef);
private readonly renderer = inject(Renderer2);

ngOnInit(): void {
if (!this.iconName() || !SVG_ICONS[this.iconName()]) {
console.error(`SVG icon not found: ${this.iconName()}`);
return;
}

const svgString = SVG_ICONS[this.iconName()];
const parser = new DOMParser();
const doc = parser.parseFromString(svgString, 'image/svg+xml');
const svgElement = doc.documentElement;

// Add CSS classes if provided
if (this.iconClass()) {const classes = this.iconClass().split(' ');
classes.forEach(className => {
if (className) {
this.renderer.addClass(svgElement, className);
}
});
}

// Set fill color for all paths
const paths = svgElement.querySelectorAll('path');
paths.forEach(path => {
path.setAttribute('fill', this.fill());
});

// Append the SVG to the host element
this.renderer.setProperty(this.el.nativeElement, 'innerHTML','');
this.renderer.appendChild(this.el.nativeElement, svgElement);
}
}



Step 3: Create Type Definitions


// types.ts
import { ICON_NAME } from "./svg-icon-constants";

// Creates a union type of all icon name values
export type Icon = (typeof ICON_NAME)[keyof typeof ICON_NAME];



Step 4: Using the SVG Directive in Components


Implement the directive in any component:


// footer.ts
import { Component } from '@angular/core';
import { SvgIcon } from '../../../shared/directives/svg/svg-icon';
import { ICON_NAME } from '../../../shared/directives/svg/svg-icon-constants';

@Component({
selector: 'app-footer',
imports: [SvgIcon],
template: `
<footer class="bg-gray-800 text-white py-8">
<div class="container mx-auto">
<div class="flex justify-center space-x-6">
<a href="

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

" target="_blank" rel="noopener noreferrer">
<span appSvgIcon [iconName]="iconName.github" iconClass="w-6 h-6"></span>
</a>
<a href="

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

" target="_blank" rel="noopener noreferrer">
<span appSvgIcon [iconName]="iconName.discord" iconClass="w-6 h-6"></span>
</a>
</div>
<p class="text-center mt-4">© 2025 DevsWhoMove. All rights reserved.</p>
</div>
</footer>
`,
standalone: true
})
export class Footer {
protected readonly iconName = ICON_NAME;
}



Technical Benefits

1. Clean, Type-Safe Templates


Before:


<a href="

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

" target="_blank">
<svg class="w-6 h-6" viewBox="0 0 24 24" xmlns="

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

"><path d="M12 .297c-6.63 0-12 5.373- 12 12 0 5.303 3.438 9.8 8.205 11.385..." fill="currentColor"></path>
</svg>
</a>




After:


<a href="

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

" target="_blank">
<span appSvgIcon [iconName]="iconName.github" iconClass="w-6 h-6"></span>
</a>



2. Developer Experience Improvements

  • Type Safety: TypeScript interfaces ensure correct icon names
  • Centralized Management: Single source of truth for all SVGs
  • IDE Support: Autocomplete for icon names and properties
  • Consistent Styling: Apply classes uniformly across all icons
3. Performance Optimizations

  • Reduced Bundle Size: No duplicate SVG definitions
  • Efficient DOM Operations: Directive handles optimal rendering
  • Caching: Browser can cache SVG content
Advanced Implementation Options

1. Server-Side Rendering Support


For Angular Universal applications, ensure the directive works with SSR by checking the platform before performing DOM operations:


import { PLATFORM_ID, inject } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';

// Modern dependency injection
private readonly platformId = inject(PLATFORM_ID);

ngOnInit(): void {
// Only perform DOM operations in browser environment
if (isPlatformBrowser(this.platformId)) {
// SVG parsing and DOM manipulation code
const svgString = SVG_ICONS[this.iconName()];
const parser = new DOMParser();
// Rest of the implementation...
}
}



2. Lazy Loading Icons by Feature


For applications with many icons, implement lazy loading by feature using modern Angular patterns:


// feature-icons.ts
import { InjectionToken } from '@angular/core';

// Create a token for feature-specific icons
export const FEATURE_ICONS = new InjectionToken<Record<string, string>>('FEATURE_ICONS');

// Define feature-specific icons
export const DASHBOARD_ICONS = {
chart: `<svg viewBox="0 0 24 24">...</svg>`,
analytics: `<svg viewBox="0 0 24 24">...</svg>`
};

// In your feature module or component providers
providers: [
{
provide: FEATURE_ICONS,
useValue: DASHBOARD_ICONS
}
]

// Inject in directive
const featureIcons = inject(FEATURE_ICONS, { optional: true });

// Merge with core icons
const allIcons = { ...SVG_ICONS, ...featureIcons };



Conclusion


Our centralized SVG handling approach in the DevsWhoRun Angular application demonstrates how modern Angular features like signals and functional dependency injection can create a clean, maintainable solution. By centralizing SVG definitions and using a directive for rendering, we've achieved:

  1. Improved Developer Experience: Type-safe icon references with IDE autocompletion
  2. Better Performance: Reduced bundle size and optimized rendering
  3. Enhanced Maintainability: Single source of truth for all SVG assets
  4. Flexible Styling: Dynamic class application and fill color control

This pattern scales well from small applications to enterprise-level projects, providing a solid foundation for consistent icon usage across your Angular applications.



Источник:

Пожалуйста Авторизируйтесь или Зарегистрируйтесь для просмотра скрытого текста.

 
Вверх Снизу