file upload - Carga de archivos desde<input type="file">
upload file angular 4 (7)
Usando angular 2 beta, parece que no puedo obtener un
<input type="file">
para trabajar.
Utilizando el diagnóstico, puedo ver el enlace bidireccional para otros
type
, como el
text
.
<form>
{{diagnostic}}
<div class="form-group">
<label for="fileupload">Upload</label>
<input type="file" class="form-control" [(ngModel)]="model.fileupload">
</div>
</form>
En mi archivo TypeScript, tengo la siguiente línea de diagnóstico:
get diagnostic() { return JSON.stringify(this.model); }
¿Podría ser que se trata de no ser JSON?
El valor es
null
.
Realmente no puedo verificar el valor de la
input
.
Aunque el texto junto a "Elegir archivo ..." se actualiza, no puedo ver diferencias en el DOM por alguna razón.
Creo que no es compatible.
Si echa un vistazo a esta directiva
DefaultValueAccessor
(consulte
https://github.com/angular/angular/blob/master/modules/angular2/src/common/forms/directives/default_value_accessor.ts#L23
).
Verá que el valor utilizado para actualizar el elemento enlazado es
$event.target.value
.
Esto no se aplica en el caso de entradas con tipo de
file
ya que se puede alcanzar el objeto de archivo
$event.srcElement.files
en
$event.srcElement.files
lugar.
Para obtener más detalles, puede echar un vistazo a este plunkr: https://plnkr.co/edit/ozZqbxIorjQW15BrDFrg?p=info :
@Component({
selector: ''my-app'',
template: `
<div>
<input type="file" (change)="onChange($event)"/>
</div>
`,
providers: [ UploadService ]
})
export class AppComponent {
onChange(event) {
var files = event.srcElement.files;
console.log(files);
}
}
Hay una forma ligeramente mejor de acceder a los archivos adjuntos. Puede usar la variable de referencia de plantilla para obtener una instancia del elemento de entrada.
Aquí hay un ejemplo basado en la primera respuesta:
@Component({
selector: ''my-app'',
template: `
<div>
<input type="file" #file (change)="onChange(file.files)"/>
</div>
`,
providers: [ UploadService ]
})
export class AppComponent {
onChange(files) {
console.log(files);
}
}
Aquí hay una aplicación de ejemplo para demostrar esto en acción.
Las variables de referencia de plantilla pueden ser útiles, por ejemplo, puede acceder a ellas a través de @ViewChild directamente en el controlador.
Otra forma de usar la variable de referencia de plantilla y ViewChild, según lo propuesto por Frelseren:
import { ViewChild } from ''@angular/core'';
@Component({
selector: ''my-app'',
template: `
<div>
<input type="file" #fileInput/>
</div>
`
})
export class AppComponent {
@ViewChild("fileInput") fileInputVariable: any;
randomMethod() {
const files = this.fileInputVariable.nativeElement.files;
console.log(files);
}
}
Consulte también https://.com/a/40165524/4361955
Prueba esta pequeña lib, funciona con Angular 5.0.0
Ejemplo de inicio rápido con ng2-file-upload 1.3.0:
El usuario hace clic en el botón personalizado, que activa el diálogo de carga desde el tipo de entrada oculto = "archivo", la carga se inicia automáticamente después de seleccionar un solo archivo.
app.module.ts:
import {FileUploadModule} from "ng2-file-upload";
your.component.html:
...
<button mat-button onclick="document.getElementById(''myFileInputField'').click()" >
Select and upload file
</button>
<input type="file" id="myFileInputField" ng2FileSelect [uploader]="uploader" style="display:none">
...
your.component.ts:
import {FileUploader} from ''ng2-file-upload'';
...
uploader: FileUploader;
...
constructor() {
this.uploader = new FileUploader({url: "/your-api/some-endpoint"});
this.uploader.onErrorItem = item => {
console.error("Failed to upload");
this.clearUploadField();
};
this.uploader.onCompleteItem = (item, response) => {
console.info("Successfully uploaded");
this.clearUploadField();
// (Optional) Parsing of response
let responseObject = JSON.parse(response) as MyCustomClass;
};
// Asks uploader to start upload file automatically after selecting file
this.uploader.onAfterAddingFile = fileItem => this.uploader.uploadAll();
}
private clearUploadField(): void {
(<HTMLInputElement>window.document.getElementById(''myFileInputField''))
.value = "";
}
Lib alternativo, funciona en Angular 4.2.4, pero requiere algunas soluciones alternativas para adoptar Angular 5.0.0
Si tiene una forma compleja con múltiples archivos y otras entradas, aquí hay una solución que funciona bien con
ngModel
.
Consiste en un componente de entrada de archivo que envuelve una entrada de archivo simple e implementa la interfaz
ControlValueAccessor
para que sea consumible por
ngModel
.
El componente expone el objeto
ngModel
a
ngModel
.
Esta solución se basa en this artículo.
El componente se usa así:
<file-input name="file" inputId="file" [(ngModel)]="user.photo"></file-input>
<label for="file"> Select file </label>
Aquí está el código del componente:
import { Component, Input, forwardRef } from ''@angular/core'';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from ''@angular/forms'';
const noop = () => {
};
export const CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => FileInputComponent),
multi: true
};
@Component({
selector: ''file-input'',
templateUrl: ''./file-input.component.html'',
providers: [CUSTOM_INPUT_CONTROL_VALUE_ACCESSOR]
})
export class FileInputComponent {
@Input()
public name:string;
@Input()
public inputId:string;
private innerValue:any;
constructor() { }
get value(): FileList {
return this.innerValue;
};
private onTouchedCallback: () => void = noop;
private onChangeCallback: (_: FileList) => void = noop;
set value(v: FileList) {
if (v !== this.innerValue) {
this.innerValue = v;
this.onChangeCallback(v);
}
}
onBlur() {
this.onTouchedCallback();
}
writeValue(value: FileList) {
if (value !== this.innerValue) {
this.innerValue = value;
}
}
registerOnChange(fn: any) {
this.onChangeCallback = fn;
}
registerOnTouched(fn: any) {
this.onTouchedCallback = fn;
}
changeFile(event) {
this.value = event.target.files;
}
}
Y aquí está la plantilla del componente:
<input type="file" name="{{ name }}" id="{{ inputId }}" multiple="multiple" (change)="changeFile($event)"/>
solo intenta
(onclick)="this.value = null"
en su página html agregue el método onclick para eliminar el valor anterior para que el usuario pueda seleccionar el mismo archivo nuevamente.
@Component({
selector: ''my-app'',
template: `
<div>
<input name="file" type="file" (change)="onChange($event)"/>
</div>
`,
providers: [ UploadService ]
})
export class AppComponent {
file: File;
onChange(event: EventTarget) {
let eventObj: MSInputMethodContext = <MSInputMethodContext> event;
let target: HTMLInputElement = <HTMLInputElement> eventObj.target;
let files: FileList = target.files;
this.file = files[0];
console.log(this.file);
}
doAnythingWithFile() {
}
}