ng-zorro-antd
ng-zorro-antd copied to clipboard
为 nz-upload 实现 ControlValueAccessor
What problem does this feature solve?
nz-upload 也属于表单控件吧,是否考虑为nz-upload实现ControlValueAccessor
What does the proposed API look like?
<nz-upload [(ngModel)]="file" required>
Translation of this issue:
Implementing ControlValueAccessor for nz-upload
What problem does this feature solve?
Nz-upload is also a form control, is it considered to implement ControlValueAccessor for nz-upload?
What does the proposed API look like?
<nz-upload [(ngModel)]="file" required>
is there any progress?
is there any update? How can I make nz-upload as a formControl field?
@mengyaolin, You can use the nzChange
event, like this:
<nz-upload (nzChange)="uploadChange($event)"></nz-upload>
uploadChange(ev: NzUploadChangeParam): void {
if (ev.type === 'success') {
this.form.patchValue({ file: ev.file.response.url })
}
}
Angular 的组件是很容易通过指令来扩展原有功能的 @mengyaolin
由于 upload 组件的值比较复杂,不建议在原有的组件上直接实现表单能力,推荐使用单独的指令来实现表单能力
这里提供一个单文件上传的表单例子(这个场景比较简单,方便理解),同理根据需要实现多文件上传的表单
用法
<nz-upload nzx [(ngModel)]="url"></nz-upload>
实现
import {
Directive,
forwardRef,
Input,
OnDestroy,
OnInit,
Self,
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { NzUploadComponent } from 'ng-zorro-antd/upload';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Directive({
// eslint-disable-next-line @angular-eslint/directive-selector
selector: 'nz-upload[nzx]',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => NzUploadExtensionDirective),
multi: true,
},
],
})
export class NzUploadExtensionDirective
implements OnInit, ControlValueAccessor, OnDestroy
{
@Input()
defaultFileName?: string;
private destroy$$ = new Subject<void>();
onChange?: (v?: string) => void;
constructor(@Self() private uploadRef: NzUploadComponent) {}
ngOnInit(): void {
this.uploadRef.nzChange
.pipe(takeUntil(this.destroy$$))
.subscribe((info) => {
if (info.type === 'removed') {
this.onChange?.();
return;
}
if (info.file.status === 'done') {
this.onChange?.(info.file.response.url);
}
});
}
ngOnDestroy(): void {
this.destroy$$.next();
this.destroy$$.complete();
}
registerOnTouched(): void {
/* 不关心 */
}
registerOnChange(fn: (v?: string) => void): void {
this.onChange = fn;
}
writeValue(v: string): void {
if (v) {
this.uploadRef.nzFileList = [
{
uid: v,
name: this.defaultFileName ?? v,
status: 'done',
url: v,
},
];
} else {
this.uploadRef.nzFileList = [];
this.uploadRef.ngOnChanges();
}
}
setDisabledState(isDisabled: boolean): void {
this.uploadRef.nzDisabled = isDisabled;
this.uploadRef.ngOnChanges();
}
}