7
7
ComponentFactoryResolver ,
8
8
ElementRef ,
9
9
EventEmitter ,
10
+ Injectable ,
10
11
Injector ,
11
12
Input ,
12
13
NgZone ,
@@ -15,18 +16,34 @@ import {
15
16
SecurityContext ,
16
17
ViewContainerRef ,
17
18
} from '@angular/core' ;
18
- import { Subscription } from 'rxjs' ;
19
- import { take } from 'rxjs/operators' ;
19
+ import { Observable , Subscription } from 'rxjs' ;
20
+ import { shareReplay , take , tap } from 'rxjs/operators' ;
20
21
import { ExampleViewer } from '../example-viewer/example-viewer' ;
21
22
import { HeaderLink } from './header-link' ;
22
23
24
+ @Injectable ( { providedIn : 'root' } )
25
+ class DocFetcher {
26
+ private _cache : Record < string , Observable < string > > = { } ;
27
+
28
+ constructor ( private _http : HttpClient ) { }
29
+
30
+ fetchDocument ( url : string ) : Observable < string > {
31
+ if ( this . _cache [ url ] ) {
32
+ return this . _cache [ url ] ;
33
+ }
34
+
35
+ const stream = this . _http . get ( url , { responseType : 'text' } ) . pipe ( shareReplay ( 1 ) ) ;
36
+ return stream . pipe ( tap ( ( ) => this . _cache [ url ] = stream ) ) ;
37
+ }
38
+ }
39
+
23
40
@Component ( {
24
41
selector : 'doc-viewer' ,
25
42
template : 'Loading document...' ,
26
43
} )
27
44
export class DocViewer implements OnDestroy {
28
45
private _portalHosts : DomPortalOutlet [ ] = [ ] ;
29
- private _documentFetchSubscription : Subscription = new Subscription ( ) ;
46
+ private _documentFetchSubscription : Subscription | undefined ;
30
47
31
48
@Input ( ) name : string | undefined ;
32
49
@@ -69,21 +86,17 @@ export class DocViewer implements OnDestroy {
69
86
constructor ( private _appRef : ApplicationRef ,
70
87
private _componentFactoryResolver : ComponentFactoryResolver ,
71
88
public _elementRef : ElementRef ,
72
- private _http : HttpClient ,
73
89
private _injector : Injector ,
74
90
private _viewContainerRef : ViewContainerRef ,
75
91
private _ngZone : NgZone ,
76
- private _domSanitizer : DomSanitizer ) {
92
+ private _domSanitizer : DomSanitizer ,
93
+ private _docFetcher : DocFetcher ) {
77
94
}
78
95
79
96
/** Fetch a document by URL. */
80
97
private _fetchDocument ( url : string ) {
81
- // Cancel previous pending request
82
- if ( this . _documentFetchSubscription ) {
83
- this . _documentFetchSubscription . unsubscribe ( ) ;
84
- }
85
-
86
- this . _documentFetchSubscription = this . _http . get ( url , { responseType : 'text' } ) . subscribe (
98
+ this . _documentFetchSubscription ?. unsubscribe ( ) ;
99
+ this . _documentFetchSubscription = this . _docFetcher . fetchDocument ( url ) . subscribe (
87
100
document => this . updateDocument ( document ) ,
88
101
error => this . showError ( url , error )
89
102
) ;
@@ -116,7 +129,7 @@ export class DocViewer implements OnDestroy {
116
129
117
130
/** Show an error that occurred when fetching a document. */
118
131
private showError ( url : string , error : HttpErrorResponse ) {
119
- console . log ( error ) ;
132
+ console . error ( error ) ;
120
133
this . _elementRef . nativeElement . innerText =
121
134
`Failed to load document: ${ url } . Error: ${ error . statusText } ` ;
122
135
}
@@ -149,9 +162,6 @@ export class DocViewer implements OnDestroy {
149
162
150
163
ngOnDestroy ( ) {
151
164
this . _clearLiveExamples ( ) ;
152
-
153
- if ( this . _documentFetchSubscription ) {
154
- this . _documentFetchSubscription . unsubscribe ( ) ;
155
- }
165
+ this . _documentFetchSubscription ?. unsubscribe ( ) ;
156
166
}
157
167
}
0 commit comments