Эта реализация работала для меня именно так, как мне нужно было с помощью 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);