Skip to content

Commit f9adcf4

Browse files
authored
Merge branch '9.0.x' into dmdimitrov/issue7343-9.0.x
2 parents 2d37dc1 + 7fc569a commit f9adcf4

File tree

3 files changed

+83
-14
lines changed

3 files changed

+83
-14
lines changed

projects/igniteui-angular/src/lib/icon/icon.component.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
import { Component, ElementRef, HostBinding, Input, OnInit, TemplateRef, ViewChild } from '@angular/core';
1+
import { Component, ElementRef, HostBinding, Input, OnInit, TemplateRef, ViewChild, ChangeDetectorRef, OnDestroy } from '@angular/core';
22
import { IgxIconService } from './icon.service';
3+
import { first, takeUntil } from 'rxjs/operators';
4+
import { Subject } from 'rxjs';
35

46
/**
57
* Icon provides a way to include material icons to markup
@@ -29,8 +31,7 @@ let NEXT_ID = 0;
2931
selector: 'igx-icon',
3032
templateUrl: 'icon.component.html'
3133
})
32-
33-
export class IgxIconComponent implements OnInit {
34+
export class IgxIconComponent implements OnInit, OnDestroy {
3435
@ViewChild('noLigature', { read: TemplateRef, static: true })
3536
private noLigature: TemplateRef<HTMLElement>;
3637

@@ -40,6 +41,8 @@ export class IgxIconComponent implements OnInit {
4041
@ViewChild('svgImage', { read: TemplateRef, static: true })
4142
private svgImage: TemplateRef<HTMLElement>;
4243

44+
private destroy$ = new Subject<void>();
45+
4346
/**
4447
* This allows you to change the value of `class.igx-icon`. By default it's `igx-icon`.
4548
*
@@ -120,10 +123,18 @@ export class IgxIconComponent implements OnInit {
120123
*/
121124
public el: ElementRef;
122125

123-
constructor(private _el: ElementRef, private iconService: IgxIconService) {
126+
constructor(
127+
private _el: ElementRef,
128+
private iconService: IgxIconService,
129+
private ref: ChangeDetectorRef) {
124130
this.el = _el;
125131
this.font = this.iconService.defaultFontSet;
126132
this.iconService.registerFontSetAlias('material', 'material-icons');
133+
this.iconService.iconLoaded.pipe(
134+
first(e => e.name === this.iconName && e.fontSet === this.font),
135+
takeUntil(this.destroy$)
136+
)
137+
.subscribe(_ => this.ref.detectChanges());
127138
}
128139

129140
/**
@@ -134,6 +145,15 @@ export class IgxIconComponent implements OnInit {
134145
this.updateIconClass();
135146
}
136147

148+
/**
149+
* @hidden
150+
* @internal
151+
*/
152+
ngOnDestroy() {
153+
this.destroy$.next();
154+
this.destroy$.complete();
155+
}
156+
137157
/**
138158
* An accessor that returns the value of the font property.
139159
* @example

projects/igniteui-angular/src/lib/icon/icon.service.spec.ts

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { IgxIconService } from './icon.service';
33
import { DOCUMENT } from '@angular/common';
44

55
import { configureTestSuite } from '../test-utils/configure-suite';
6+
import { first } from 'rxjs/operators';
67

78
describe('Icon Service', () => {
89
configureTestSuite();
@@ -21,38 +22,38 @@ describe('Icon Service', () => {
2122
});
2223

2324
it('should set the default icon set', () => {
24-
const iconService = TestBed.get(IgxIconService);
25+
const iconService = TestBed.inject(IgxIconService);
2526

2627
expect(() => {
2728
iconService.defaultFontSet = MY_FONT;
2829
}).not.toThrow();
2930
});
3031

3132
it('should get the default icon set', () => {
32-
const iconService = TestBed.get(IgxIconService);
33+
const iconService = TestBed.inject(IgxIconService);
3334
iconService.defaultFontSet = MY_FONT;
3435

3536
expect(iconService.defaultFontSet).toBe(MY_FONT);
3637
});
3738

3839
it('should associate alias name with icon set name', () => {
39-
const iconService = TestBed.get(IgxIconService);
40+
const iconService = TestBed.inject(IgxIconService);
4041

4142
expect(() => {
4243
iconService.registerFontSetAlias(ALIAS, MY_FONT);
4344
}).not.toThrow();
4445
});
4546

4647
it('should get icon set name from alias name', () => {
47-
const iconService = TestBed.get(IgxIconService);
48+
const iconService = TestBed.inject(IgxIconService);
4849
iconService.registerFontSetAlias(ALIAS, MY_FONT);
4950

5051
expect(iconService.fontSetClassName(ALIAS)).toBe(MY_FONT);
5152
});
5253

5354
it('should add custom svg icon from url', () => {
54-
const iconService = TestBed.get(IgxIconService) as IgxIconService;
55-
const document = TestBed.get(DOCUMENT);
55+
const iconService = TestBed.inject(IgxIconService) as IgxIconService;
56+
const document = TestBed.inject(DOCUMENT);
5657

5758
const iconName = 'test';
5859
const fontSet = 'svg-icons';
@@ -71,8 +72,8 @@ describe('Icon Service', () => {
7172
});
7273

7374
it('should add custom svg icon from text', () => {
74-
const iconService = TestBed.get(IgxIconService) as IgxIconService;
75-
const document = TestBed.get(DOCUMENT);
75+
const iconService = TestBed.inject(IgxIconService) as IgxIconService;
76+
const document = TestBed.inject(DOCUMENT);
7677

7778
const iconName = 'test';
7879
const fontSet = 'svg-icons';
@@ -86,4 +87,28 @@ describe('Icon Service', () => {
8687
const svgElement = document.querySelector(`svg[id='${iconKey}']`);
8788
expect(svgElement).toBeDefined();
8889
});
90+
91+
it('should emit loading event for a custom svg icon from url', done => {
92+
const iconService = TestBed.inject(IgxIconService) as IgxIconService;
93+
94+
iconService.iconLoaded.pipe(first()).subscribe(event => {
95+
expect(event.name).toMatch('test');
96+
expect(event.fontSet).toMatch('svg-icons');
97+
done();
98+
});
99+
100+
const iconName = 'test';
101+
const fontSet = 'svg-icons';
102+
103+
spyOn(XMLHttpRequest.prototype, 'open').and.callThrough();
104+
spyOn(XMLHttpRequest.prototype, 'send').and.callFake(() => {
105+
(iconService as any)._iconLoaded.next({
106+
name: iconName,
107+
value: svgText,
108+
fontSet: fontSet
109+
});
110+
});
111+
112+
iconService.addSvgIcon(iconName, 'test.svg', fontSet);
113+
});
89114
});

projects/igniteui-angular/src/lib/icon/icon.service.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
import { Injectable, SecurityContext, Inject } from '@angular/core';
22
import { DomSanitizer } from '@angular/platform-browser';
33
import { DOCUMENT } from '@angular/common';
4+
import { Subject } from 'rxjs';
5+
6+
/**
7+
* Event emitted when a SVG icon is loaded through
8+
* a HTTP request.
9+
*/
10+
export interface IgxIconLoadedEvent {
11+
/** Name of the icon */
12+
name: string;
13+
/** The actual SVG text */
14+
value: string;
15+
/** The fontSet for the icon. Defaults to material. */
16+
fontSet: string;
17+
}
418

519
/**
620
* **Ignite UI for Angular Icon Service** -
@@ -14,16 +28,25 @@ import { DOCUMENT } from '@angular/common';
1428
* this.iconService.addSvgIcon('aruba', '/assets/svg/country_flags/aruba.svg', 'svg-flags');
1529
* ```
1630
*/
17-
1831
@Injectable({
1932
providedIn: 'root'
2033
})
21-
2234
export class IgxIconService {
2335
private _fontSet = 'material-icons';
2436
private _fontSetAliases = new Map<string, string>();
2537
private _svgContainer: HTMLElement;
2638
private _cachedSvgIcons: Set<string> = new Set<string>();
39+
private _iconLoaded = new Subject<IgxIconLoadedEvent>();
40+
41+
/**
42+
* Observable that emits when an icon is successfully loaded
43+
* through a HTTP request.
44+
* @example
45+
* ```typescript
46+
* this.service.iconLoaded.subscribe((ev: IgxIconLoadedEvent) => ...);
47+
* ```
48+
*/
49+
public iconLoaded = this._iconLoaded.asObservable();
2750

2851
constructor(private _sanitizer: DomSanitizer, @Inject(DOCUMENT) private _document: any) { }
2952

@@ -143,6 +166,7 @@ export class IgxIconService {
143166
const request = event.target as XMLHttpRequest;
144167
if (request.status === 200) {
145168
instance.cacheSvgIcon(iconName, request.responseText, fontSet);
169+
instance._iconLoaded.next({ name: iconName, value: request.responseText, fontSet });
146170
} else {
147171
throw new Error(`Could not fetch SVG from url: ${url}; error: ${request.status} (${request.statusText})`);
148172
}

0 commit comments

Comments
 (0)