@@ -4,18 +4,19 @@ import {
44 AfterViewInit ,
55 ChangeDetectionStrategy ,
66 Component ,
7+ effect ,
78 ElementRef ,
9+ inject ,
810 Injector ,
11+ input ,
912 OnDestroy ,
1013 PLATFORM_ID ,
11- Renderer2 ,
12- effect ,
13- inject ,
14- input ,
15- untracked ,
14+ Renderer2
1615} from '@angular/core' ;
1716import { getZoneUnPatchedApi } from './internal/get-zone-unpatched-api' ;
1817import { SvgRegistry } from './svg-registry.service' ;
18+ import { toObservable , toSignal } from '@angular/core/rxjs-interop' ;
19+ import { of , switchMap } from 'rxjs' ;
1920
2021/**
2122 * getZoneUnPatchedApi
@@ -110,6 +111,11 @@ export class FastSvgComponent implements AfterViewInit, OnDestroy {
110111 width = input < string > ( '' ) ;
111112 height = input < string > ( '' ) ;
112113
114+ #url = toSignal ( toObservable ( this . name ) . pipe ( switchMap ( ( name ) => {
115+ const url = this . registry . url ( name ) ;
116+ return typeof url === 'string' ? of ( url ) : url ;
117+ } ) ) )
118+
113119 // When the browser loaded the svg resource we trigger the caching mechanism
114120 // re-fetch -> cache-hit -> get SVG -> cache in DOM
115121 loadedListener = ( ) => {
@@ -142,7 +148,6 @@ export class FastSvgComponent implements AfterViewInit, OnDestroy {
142148 ( onCleanup ) => {
143149 const name = this . name ( ) ;
144150
145- untracked ( ( ) => {
146151 if ( ! name ) {
147152 throw new Error ( 'svg component needs a name to operate' ) ;
148153 }
@@ -153,32 +158,35 @@ export class FastSvgComponent implements AfterViewInit, OnDestroy {
153158 if ( ! this . registry . isSvgCached ( name ) ) {
154159 /**
155160 CSR - Browser native lazy loading hack
156-
161+
157162 We use an img element here to leverage the browsers native features:
158163 - lazy loading (loading="lazy") to only load the svg that are actually visible
159164 - priority hints to down prioritize the fetch to avoid delaying the LCP
160-
165+
161166 While the SVG is loading we display a fallback SVG.
162167 After the image is loaded we remove it from the DOM. (IMG load event)
163168 When the new svg arrives we append it to the template.
164-
169+
165170 Note:
166171 - the image is styled with display none. this prevents any loading of the resource ever.
167172 on component bootstrap we decide what we want to do. when we remove display none it performs the browser native behavior
168- - the image has 0 height and with and containment as well as contnet -visibility to reduce any performance impact
169-
170-
173+ - the image has 0 height and with and containment as well as content -visibility to reduce any performance impact
174+
175+
171176 Edge cases:
172177 - only resources that are not loaded in the current session of the browser will get lazy loaded (same URL to trigger loading is not possible)
173178 - already loaded resources will get emitted from the cache immediately, even if loading is set to lazy :o
174179 - the image needs to have display other than none
175180 */
176- const i = this . getImg ( this . registry . url ( name ) ) ;
177- this . renderer . appendChild ( this . element . nativeElement , i ) ;
178-
179- // get img
180- img = elem . querySelector ( 'img' ) as HTMLImageElement ;
181- addEventListener ( img , 'load' , this . loadedListener ) ;
181+ const url = this . #url( ) ;
182+ if ( url ) {
183+ const i = this . getImg ( url ) ;
184+ this . renderer . appendChild ( this . element . nativeElement , i ) ;
185+
186+ // get img
187+ img = elem . querySelector ( 'img' ) as HTMLImageElement ;
188+ addEventListener ( img , 'load' , this . loadedListener ) ;
189+ }
182190 }
183191
184192 // Listen to svg changes
@@ -225,7 +233,6 @@ export class FastSvgComponent implements AfterViewInit, OnDestroy {
225233 img . removeEventListener ( 'load' , this . loadedListener ) ;
226234 }
227235 } ) ;
228- } ) ;
229236 } ,
230237 { injector : this . injector }
231238 ) ;
0 commit comments