Angular中如何通过代码设置文件输入框的已选文件名?
问题
我有一个带模态对话框的Angular应用,模态框内包含文件输入字段及“Next”和“Back”按钮。选择文件后进入下一个视图,返回上传文件对话框时,希望在输入框中显示之前选中的文件,但目前出现以下错误:
ERROR DOMException: Failed to set the 'value' property on 'HTMLInputElement': This input element accepts a filename, which may only be programmatically set to the empty string.
相关代码如下:
<ds-modal> <ds-box-content> <ds-form-field> <label ds-label for="file">Excel-File</label> <input ds-input #fileInput id="file" type="file" formControlName="file" [accept]="acceptFileType" [labellingConfig]="labellingConfig" (change)="extractUploadedFile($event)" required /> </ds-form-field> </ds-box-content> <button ds-button *ngIf="showBackButton$ | async" [variant]="'outline'" class="modal-button" (click)="onBackClick()" > Back </button> </ds-modal>
export class MyComponent implements OnInit, AfterViewInit { @ViewChild('fileInput') fileInputRef!: ElementRef; maxSize = 10; acceptFileType: string = '.xlsx'; labellingConfig: DsInputLabellingConfig = { empty: 'No File selected', addFilesSingle: 'Add file', fileCounter: '', addFilesMultiple: '' }; selectedFileType: string = FileTypeEnum.EXCEL; reactiveForm = new FormGroup({ file: new FormControl('', { validators: [Validators.required], }) }); uploadedXlsxFile?: File; onBackClick() { this.selectedFileType = this.savedFileType ?? FileTypeEnum.EXCEL; this.uploadedXlsxFile = this.savedUploadedXlsxFile; if (this.uploadedXlsxFile) { this.reactiveForm.controls['file'].setValue(this.uploadedXlsxFile.name); } else { this.reactiveForm.controls['file'].reset(); } } }
解决方案
浏览器出于安全限制,禁止通过代码直接设置type="file"输入框的value(仅允许设为空字符串),因此无法通过表单控件赋值来显示历史选中的文件名。推荐以下两种实现方式:
1. 利用组件自带的labellingConfig自定义显示文本
你的ds-input组件支持labellingConfig配置,返回上传视图时,直接修改配置文本为已选中的文件名即可:
onBackClick() { this.selectedFileType = this.savedFileType ?? FileTypeEnum.EXCEL; this.uploadedXlsxFile = this.savedUploadedXlsxFile; if (this.uploadedXlsxFile) { // 更新配置,用文件名替换空状态提示 this.labellingConfig = { ...this.labellingConfig, empty: this.uploadedXlsxFile.name }; // 表单控件直接绑定文件对象,而非文件名 this.reactiveForm.controls['file'].setValue(this.uploadedXlsxFile); } else { // 恢复默认提示文本 this.labellingConfig = { ...this.labellingConfig, empty: 'No File selected' }; this.reactiveForm.controls['file'].reset(); } }
同时在文件选择方法中保存文件对象和类型:
extractUploadedFile(event: Event) { const input = event.target as HTMLInputElement; if (input.files?.length) { this.uploadedXlsxFile = input.files[0]; this.savedUploadedXlsxFile = this.uploadedXlsxFile; this.savedFileType = this.selectedFileType; // 选中文件后立即更新显示文本 this.labellingConfig = { ...this.labellingConfig, empty: this.uploadedXlsxFile.name }; this.reactiveForm.controls['file'].setValue(this.uploadedXlsxFile); } }
2. 隐藏原生输入,自定义UI展示
如果组件配置不够灵活,可以隐藏原生文件输入框,用自定义元素显示文件名,点击时触发原生选择逻辑:
- 修改模板:
<ds-form-field> <label ds-label for="file">Excel-File</label> <!-- 隐藏原生文件输入 --> <input ds-input #fileInput id="file" type="file" formControlName="file" [accept]="acceptFileType" (change)="extractUploadedFile($event)" required style="display: none;" /> <!-- 自定义可点击的显示区域 --> <div ds-input (click)="fileInputRef.nativeElement.click()" style="cursor: pointer;"> {{ uploadedXlsxFile?.name || 'No File selected' }} </div> </ds-form-field>
- 组件逻辑只需确保
uploadedXlsxFile在返回时被正确恢复即可,无需修改表单值的设置逻辑。
关键注意点
- 提交表单时,直接使用保存的
uploadedXlsxFile对象,不要依赖表单控件的value(原生file输入的value无法被代码正确设置)。 - 仅能通过用户手动选择文件更新
uploadedXlsxFile,代码中只能恢复该对象的引用,不能通过设置输入框value实现回显。
内容的提问来源于stack exchange,提问作者LDropl
相关产品推荐
相关产品推荐

