我需要将CSV文件的内容保存在我的反应式表单中,作为表单控件的输入值。当前默认情况下仅选择文件名,我需要保存该Form Control的文件数据,而不仅仅是文件名。
我尝试了此处提到的一种方法:Angular 7 : How do I submit file/image along with my reactive form?
表示用文件数据修补Form Control值。当我尝试采用这种方法时,出现以下错误:
错误DOMException:无法在上设置'value'属性 'HTMLInputElement':此输入元素接受文件名,该文件名可能 只能以编程方式设置为空字符串。 在EmulatedEncapsulationDomRenderer2.push ../ node_modules/@angular/platform-browser/fesm5/platform-browser.js.DefaultDomRenderer2.setProperty (http://localhost:4200/vendor.js:134583:18) 在BaseAnimationRenderer.push ../ node_modules/@angular/platform-browser/fesm5/animations.js.BaseAnimationRenderer.setProperty中 (http://localhost:4200/vendor.js:133181:27) 在DebugRenderer2.push ../ node_modules/@angular/core/fesm5/core.js.DebugRenderer2.setProperty (http://localhost:4200/vendor.js:85257:23) 在DefaultValueAccessor.push ../ node_modules/@angular/forms/fesm5/forms.js.DefaultValueAccessor.writeValue(http://localhost:4200/vendor.js:86345:24)中 在http://localhost:4200/vendor.js:87606:27 在http://localhost:4200/vendor.js:88761:65 在Array.forEach() 在FormControl.push ../ node_modules/@angular/forms/fesm5/forms.js.FormControl.setValue (http://localhost:4200/vendor.js:88761:28) 在FormControl.push ../ node_modules/@angular/forms/fesm5/forms.js.FormControl.patchValue (http://localhost:4200/vendor.js:88776:14) 在http://localhost:4200/vendor.js:89118:38
onFileChange(event, formCotrolKey: string) {
if (event.target.files && event.target.files.length) {
const [file] = event.target.files;
this.formGroup.patchValue({
[formCotrolKey]: file
});
// need to run CD since file load runs outside of zone
this.changeDetectorRef.markForCheck();
}
}
答案 0 :(得分:0)
尝试一下:
HTML :
<input #fileInput type="file" name="document" [(ngModel)]="file" />
打字稿:
@ViewChild("fileInput") fileInput;
onFileChange() {
let fi = this.fileInput.nativeElement;
if (fi.files && fi.files[0]) {
let fileToUpload = fi.files[0];
}
}
我们将在变量 fileToUpload
中获取文件答案 1 :(得分:0)
此实现完全符合我使用ControlValueAccessor所需的要求。为此,您只需要创建一个实现ControlValueAccessor接口的指令即可。
在下面使用以下代码:
import { ControlValueAccessor } from '@angular/forms';
import { Directive } from '@angular/core';
import { ElementRef } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { ChangeDetectorRef } from '@angular/core';
let noop = () => {
};
@Directive({
selector: 'input[type=file][observeFiles]',
host: {
'(blur)': 'onTouchedCallback()',
'(change)': 'handleChange( $event.target.files )'
},
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: FileInputValueAccessorDirective,
multi: true
}
]
})
export class FileInputValueAccessorDirective implements ControlValueAccessor {
private elementRef: ElementRef;
private onChangeCallback: Function;
private onTouchedCallback: Function;
// I initialize the file-input value accessor service.
constructor(elementRef: ElementRef,
private changeDetectorRef: ChangeDetectorRef) {
this.elementRef = elementRef;
this.onChangeCallback = noop;
this.onTouchedCallback = noop;
}
public handleChange(files: FileList): void {
if (this.elementRef.nativeElement.multiple) {
this.onChangeCallback(Array.from(files));
} else {
const reader = new FileReader();
reader.readAsDataURL(files[0]);
reader.onload = () => {
this.onChangeCallback(files.length ? reader.result.toString().split(',')[1] : null);
this.changeDetectorRef.markForCheck();
};
}
}
public registerOnChange(callback: Function): void {
this.onChangeCallback = callback;
}
public registerOnTouched(callback: Function): void {
this.onTouchedCallback = callback;
}
// I set the disabled property of the file input element.
public setDisabledState(isDisabled: boolean): void {
this.elementRef.nativeElement.disabled = isDisabled;
}
public writeValue(value: any): void {
if (value instanceof FileList) {
this.elementRef.nativeElement.files = value;
} else if (Array.isArray(value) && !value.length) {
this.elementRef.nativeElement.files = null;
} else if (value === null) {
this.elementRef.nativeElement.files = null;
} else {
if (console && console.warn && console.log) {
console.log('Ignoring attempt to assign non-FileList to input[type=file].');
console.log('Value:', value);
}
}
}
}
现在将此指令包含在模块数组中的声明数组下:
// Your Directive location
import { FileInputValueAccessorDirective } from 'app/forms/accessors/file-input.accessor';
@NgModule({
...
declarations: [
...
FileInputValueAccessorDirective
]
})
最后在您的组件模板中使用:
<input observeFiles [(ngModel)]="fileContent" type="file" />
确保组件中具有变量fileContent来保存数据。这就是全部。数据将以base 64格式保存在变量fileContent中。
如果不需要base 64编码,则可以在指令中替换以下行:
this.onChangeCallback(files.length ? reader.result.toString().split(',')[1] : null);
在reader.onload
方法内,此行:
this.onChangeCallback(files.length ? atob( reader.result.toString().split(',')[1] ) : null);