Skip to content

Commit 3fa7246

Browse files
committed
feat(lib): add support for showing error message on element load error
1 parent 7c328a5 commit 3fa7246

File tree

4 files changed

+91
-6
lines changed

4 files changed

+91
-6
lines changed

projects/elements/src/lib/lazy-elements/lazy-element/lazy-element.directive.spec.ts

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,25 @@ import { LazyElementDirective } from './lazy-element.directive';
2323
<p class="loading">Loading...</p>
2424
</ng-template>
2525
<some-element
26-
*axLazyElement="'http://elements.com/some-element'; loading: loading"
26+
*axLazyElement="
27+
'http://elements.com/some-element';
28+
loadingTemplate: loading
29+
"
30+
></some-element>
31+
</div>
32+
<div *ngIf="useErrorTemplate">
33+
<ng-template #loading>
34+
<p class="loading">Loading...</p>
35+
</ng-template>
36+
<ng-template #error>
37+
<p class="error">Loading failed...</p>
38+
</ng-template>
39+
<some-element
40+
*axLazyElement="
41+
'http://elements.com/some-element';
42+
loadingTemplate: loading;
43+
errorTemplate: error
44+
"
2745
></some-element>
2846
</div>
2947
<div *ngIf="useModule">
@@ -37,6 +55,7 @@ class TestHostComponent {
3755
addSameElement = false;
3856
addOtherElement = false;
3957
useLoadingTemplate = false;
58+
useErrorTemplate = false;
4059
useModule = false;
4160
}
4261

@@ -120,6 +139,35 @@ describe('LazyElementDirective', () => {
120139
});
121140
});
122141

142+
it('renders error template loading of element failed', done => {
143+
const consoleErrorSpy: jasmine.Spy = spyOn(console, 'error').and.stub();
144+
expect(document.querySelector('.loading')).toBe(null);
145+
expect(document.querySelector('.error')).toBe(null);
146+
147+
testHostComponent.useErrorTemplate = true;
148+
fixture.detectChanges();
149+
150+
expect(document.querySelector('.loading').textContent).toBe('Loading...');
151+
expect(document.querySelector('.error')).toBe(null);
152+
153+
appendChildSpy.calls.argsFor(0)[0].onerror('404');
154+
155+
fixture.detectChanges();
156+
157+
setTimeout(() => {
158+
expect(consoleErrorSpy).toHaveBeenCalledTimes(1);
159+
expect(consoleErrorSpy).toHaveBeenCalledWith(
160+
'@angular-extensions/elements - Loading of element <some-element> failed, please provide <ng-template #error>Loading failed...</ng-template> and reference it in *axLazyElement="errorTemplate: error" to display customized error message in place of element'
161+
);
162+
expect(document.querySelector('.loading')).toBe(null);
163+
expect(document.querySelector('.error').textContent).toBe(
164+
'Loading failed...'
165+
);
166+
consoleErrorSpy.and.callThrough();
167+
done();
168+
});
169+
});
170+
123171
it('uses type module on script tag when specified', () => {
124172
fixture.detectChanges();
125173

projects/elements/src/lib/lazy-elements/lazy-element/lazy-element.directive.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,15 @@ import {
88

99
import { LazyElementsLoaderService } from '../lazy-elements-loader.service';
1010

11+
const LOG_PREFIX = '@angular-extensions/elements';
12+
1113
@Directive({
1214
selector: '[axLazyElement]'
1315
})
1416
export class LazyElementDirective implements OnInit {
1517
@Input('axLazyElement') url: string;
16-
@Input('axLazyElementLoading') loadingTemplateRef: TemplateRef<any>; // tslint:disable-line:no-input-rename
18+
@Input('axLazyElementLoadingTemplate') loadingTemplateRef: TemplateRef<any>; // tslint:disable-line:no-input-rename
19+
@Input('axLazyElementErrorTemplate') errorTemplateRef: TemplateRef<any>; // tslint:disable-line:no-input-rename
1720
@Input('axLazyElementModule') isModule: boolean; // tslint:disable-line:no-input-rename
1821

1922
constructor(
@@ -35,6 +38,16 @@ export class LazyElementDirective implements OnInit {
3538
.then(() => {
3639
this.vcr.clear();
3740
this.vcr.createEmbeddedView(this.template);
41+
})
42+
.catch(() => {
43+
this.vcr.clear();
44+
if (this.errorTemplateRef) {
45+
this.vcr.createEmbeddedView(this.errorTemplateRef);
46+
} else {
47+
console.error(
48+
`${LOG_PREFIX} - Loading of element <${elementTag}> failed, please provide <ng-template #error>Loading failed...</ng-template> and reference it in *axLazyElement="errorTemplate: error" to display customized error message in place of element`
49+
);
50+
}
3851
});
3952
}
4053
}

projects/elements/src/lib/lazy-elements/lazy-elements-loader.service.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,24 @@ describe('LazyElementsLoaderService', () => {
8181
});
8282
});
8383

84+
it('rejects promise once element bundle loading failed', done => {
85+
const promise = service.loadElement(
86+
'http://elements.com/some-element',
87+
'some-element'
88+
);
89+
90+
appendChildSpy.calls.argsFor(0)[0].onerror('404');
91+
92+
promise
93+
.then(() => {
94+
fail('should reject promise instead');
95+
})
96+
.catch(error => {
97+
expect(error).toBe('404');
98+
done();
99+
});
100+
});
101+
84102
it('adds a script tag without module type', () => {
85103
service.loadElement('http://elements.com/some-element', 'some-element');
86104

projects/elements/src/lib/lazy-elements/lazy-elements-loader.service.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,19 @@ export class LazyElementsLoaderService {
3232
script.type = 'module';
3333
}
3434
script.src = url;
35-
script.onload = notifier;
35+
script.onload = notifier.resolve;
36+
script.onerror = notifier.reject;
3637
document.body.appendChild(script);
3738
}
3839

3940
return this.registry.get(this.stripUrlProtocol(url));
4041
}
4142

42-
private addElement(url: string): () => void {
43-
let notifier;
43+
private addElement(url: string): Notifier {
44+
let notifier: Notifier;
4445
this.registry.set(
4546
this.stripUrlProtocol(url),
46-
new Promise<void>(resolve => (notifier = resolve))
47+
new Promise<void>((resolve, reject) => (notifier = { resolve, reject }))
4748
);
4849
return notifier;
4950
}
@@ -56,3 +57,8 @@ export class LazyElementsLoaderService {
5657
return url.replace(/https?:\/\//, '');
5758
}
5859
}
60+
61+
interface Notifier {
62+
resolve: () => void;
63+
reject: (error: any) => void;
64+
}

0 commit comments

Comments
 (0)