From 54a441ef71c5f468936a50f93dbd0a58d43d6f0e Mon Sep 17 00:00:00 2001 From: Hsuan Lee Date: Fri, 9 Aug 2019 12:16:59 +0800 Subject: [PATCH] feat(module:avatar): support image load error event (#3893) close #3223 --- components/avatar/avatar.spec.ts | 33 +++++++++++++++++++--- components/avatar/doc/index.en-US.md | 1 + components/avatar/doc/index.zh-CN.md | 1 + components/avatar/nz-avatar.component.html | 2 +- components/avatar/nz-avatar.component.ts | 26 ++++++++++------- 5 files changed, 48 insertions(+), 15 deletions(-) diff --git a/components/avatar/avatar.spec.ts b/components/avatar/avatar.spec.ts index 071e209a339..e43d5668a86 100644 --- a/components/avatar/avatar.spec.ts +++ b/components/avatar/avatar.spec.ts @@ -1,6 +1,7 @@ import { Component, DebugElement, ViewChild } from '@angular/core'; import { fakeAsync, tick, ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; +import { createFakeEvent } from 'ng-zorro-antd/core'; import { NzIconTestModule } from 'ng-zorro-antd/icon/testing'; @@ -38,11 +39,12 @@ describe('avatar', () => { expect(context).not.toBeNull(); }); it('should tolerate error src', fakeAsync(() => { + const event = createFakeEvent('error'); expect(getType(dl)).toBe('image'); expect(context.comp.hasSrc).toBe(true); // Manually dispatch error. context.nzSrc = ''; - context.comp.imgError(); + context.comp.imgError(event); tick(); fixture.detectChanges(); expect(getType(dl)).toBe('icon'); @@ -55,6 +57,26 @@ describe('avatar', () => { expect(getType(dl)).toBe('image'); tick(); })); + it('should prevent default fallback when error src', fakeAsync(() => { + const event = createFakeEvent('error'); + event.preventDefault(); + expect(getType(dl)).toBe('image'); + expect(context.comp.hasSrc).toBe(true); + // Manually dispatch error. + context.nzSrc = 'Invalid image src'; + context.comp.imgError(event); + tick(); + fixture.detectChanges(); + expect(getType(dl)).toBe('image'); + expect(context.comp.hasSrc).toBe(true); + context.nzSrc = + 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+P+/HgAFhAJ/wlseKgAAAABJRU5ErkJggg=='; + tick(); + fixture.detectChanges(); + expect(context.comp.hasSrc).toBe(true); + expect(getType(dl)).toBe('image'); + tick(); + })); it('#nzSrcSet', () => { context.nzSrcSet = '1.png'; fixture.detectChanges(); @@ -164,27 +186,30 @@ describe('avatar', () => { expect(getType(dl)).toBe('image'); }); it('should be show icon when image loaded error and icon exists', fakeAsync(() => { + const event = createFakeEvent('error'); expect(getType(dl)).toBe('image'); - context.comp.imgError(); + context.comp.imgError(event); tick(); fixture.detectChanges(); expect(getType(dl)).toBe('icon'); })); it('should be show text when image loaded error and icon not exists', fakeAsync(() => { + const event = createFakeEvent('error'); expect(getType(dl)).toBe('image'); context.nzIcon = null; fixture.detectChanges(); - context.comp.imgError(); + context.comp.imgError(event); tick(); fixture.detectChanges(); expect(getType(dl)).toBe('text'); })); it('should be show empty when image loaded error and icon & text not exists', fakeAsync(() => { + const event = createFakeEvent('error'); expect(getType(dl)).toBe('image'); context.nzIcon = null; context.nzText = null; fixture.detectChanges(); - context.comp.imgError(); + context.comp.imgError(event); tick(); fixture.detectChanges(); expect(getType(dl)).toBe(''); diff --git a/components/avatar/doc/index.en-US.md b/components/avatar/doc/index.en-US.md index a8334f20562..8d7eedc83c6 100644 --- a/components/avatar/doc/index.en-US.md +++ b/components/avatar/doc/index.en-US.md @@ -27,3 +27,4 @@ import { NzAvatarModule } from 'ng-zorro-antd/avatar'; | `[nzSrcSet]` | a list of sources to use for different screen resolutions | string | - | | `[nzAlt]` | This attribute defines the alternative text describing the image | string | - | | `[nzText]` | letter type avatar | `string` | - | +| `(nzError)` | handler when img load error, call the `preventDefault` method to prevent default fallback behavior | `EventEmitter` | - | diff --git a/components/avatar/doc/index.zh-CN.md b/components/avatar/doc/index.zh-CN.md index 362603fc0de..1429878726d 100644 --- a/components/avatar/doc/index.zh-CN.md +++ b/components/avatar/doc/index.zh-CN.md @@ -28,3 +28,4 @@ import { NzAvatarModule } from 'ng-zorro-antd/avatar'; | `[nzSrcSet]` | 设置图片类头像响应式资源地址 | string | - | | `[nzAlt]` | 图像无法显示时的替代文本 | string | - | | `[nzText]` | 文本类头像 | `string` | - | +| `(nzError)` | 图片加载失败的事件,调用 `preventDefault` 方法会阻止组件默认的 fallback 行为 | `EventEmitter` | - | diff --git a/components/avatar/nz-avatar.component.html b/components/avatar/nz-avatar.component.html index 79d77970e7a..7d8fdc64b32 100644 --- a/components/avatar/nz-avatar.component.html +++ b/components/avatar/nz-avatar.component.html @@ -1,3 +1,3 @@ - + {{ nzText }} \ No newline at end of file diff --git a/components/avatar/nz-avatar.component.ts b/components/avatar/nz-avatar.component.ts index cdc3a0893ea..15d8b260ba8 100644 --- a/components/avatar/nz-avatar.component.ts +++ b/components/avatar/nz-avatar.component.ts @@ -12,8 +12,10 @@ import { ChangeDetectorRef, Component, ElementRef, + EventEmitter, Input, OnChanges, + Output, Renderer2, SimpleChanges, ViewChild, @@ -46,6 +48,7 @@ export class NzAvatarComponent implements OnChanges { @Input() nzSrcSet: string; @Input() nzAlt: string; @Input() nzIcon: string; + @Output() readonly nzError = new EventEmitter(); oldAPIIcon = true; // Make the user defined icon compatible to old API. Should be removed in 2.0. hasText: boolean = false; @@ -80,17 +83,20 @@ export class NzAvatarComponent implements OnChanges { return this; } - imgError(): void { - this.hasSrc = false; - this.hasIcon = false; - this.hasText = false; - if (this.nzIcon) { - this.hasIcon = true; - } else if (this.nzText) { - this.hasText = true; + imgError($event: Event): void { + this.nzError.emit($event); + if (!$event.defaultPrevented) { + this.hasSrc = false; + this.hasIcon = false; + this.hasText = false; + if (this.nzIcon) { + this.hasIcon = true; + } else if (this.nzText) { + this.hasText = true; + } + this.setClass().notifyCalc(); + this.setSizeStyle(); } - this.setClass().notifyCalc(); - this.setSizeStyle(); } ngOnChanges(changes: SimpleChanges): void {