Caricamento file in angolare?


Risposte:


375

Angular 2 offre un buon supporto per il caricamento di file. Non è richiesta alcuna libreria di terze parti.

<input type="file" (change)="fileChange($event)" placeholder="Upload file" accept=".pdf,.doc,.docx">
fileChange(event) {
    let fileList: FileList = event.target.files;
    if(fileList.length > 0) {
        let file: File = fileList[0];
        let formData:FormData = new FormData();
        formData.append('uploadFile', file, file.name);
        let headers = new Headers();
        /** In Angular 5, including the header Content-Type can invalidate your request */
        headers.append('Content-Type', 'multipart/form-data');
        headers.append('Accept', 'application/json');
        let options = new RequestOptions({ headers: headers });
        this.http.post(`${this.apiEndPoint}`, formData, options)
            .map(res => res.json())
            .catch(error => Observable.throw(error))
            .subscribe(
                data => console.log('success'),
                error => console.log(error)
            )
    }
}

utilizzando @ angular / core ":" ~ 2.0.0 "e @ angular / http:" ~ 2.0.0 "


5
non funziona, almeno nel mio caso. Il server sailsJs riceve un array / oggetto di file vuoto
Kaleem Ullah

20
Ha funzionato per me tranne - ho dovuto lavorare su questa linea - headers.append('enctype', 'multipart/form-data'); riga (usato 'enctype' per sostituire 'Content-Type'). Forse dipende dal codice lato server. (ie api)
Ariful Islam

29
Sii fantastico se il team angolare scrivesse della documentazione sull'argomento, non riesco a trovare una sola riga al riguardo nei loro documenti. Questo esempio di codice non è aggiornato e non funziona con v4 +.
Rob B

10
Nota per alcuni server applicazioni, l'impostazione del tipo di contenuto verrà rifiutata. Devi lasciare che sia vuoto: let headers = new Headers (); Il browser risolverà tutto per te.
PeterS,

6
LMFAO ha lottato per 20 minuti con questa merda fino a quando ho capito che non avevo bisogno di impostare le intestazioni. Nota agli altri che usano angular 4.xx con .Net webapi, non provare a impostare le intestazioni! Grazie per averlo sottolineato @PeterS
Jota.Toledo,

76

Dalle risposte sopra ho creato questo con Angular 5.x

Basta chiamare uploadFile(url, file).subscribe()per attivare un caricamento

import { Injectable } from '@angular/core';
import {HttpClient, HttpParams, HttpRequest, HttpEvent} from '@angular/common/http';
import {Observable} from "rxjs";

@Injectable()
export class UploadService {

  constructor(private http: HttpClient) { }

  // file from event.target.files[0]
  uploadFile(url: string, file: File): Observable<HttpEvent<any>> {

    let formData = new FormData();
    formData.append('upload', file);

    let params = new HttpParams();

    const options = {
      params: params,
      reportProgress: true,
    };

    const req = new HttpRequest('POST', url, formData, options);
    return this.http.request(req);
  }
}

Usalo così nel tuo componente

  // At the drag drop area
  // (drop)="onDropFile($event)"
  onDropFile(event: DragEvent) {
    event.preventDefault();
    this.uploadFile(event.dataTransfer.files);
  }

  // At the drag drop area
  // (dragover)="onDragOverFile($event)"
  onDragOverFile(event) {
    event.stopPropagation();
    event.preventDefault();
  }

  // At the file input element
  // (change)="selectFile($event)"
  selectFile(event) {
    this.uploadFile(event.target.files);
  }

  uploadFile(files: FileList) {
    if (files.length == 0) {
      console.log("No file selected!");
      return

    }
    let file: File = files[0];

    this.upload.uploadFile(this.appCfg.baseUrl + "/api/flash/upload", file)
      .subscribe(
        event => {
          if (event.type == HttpEventType.UploadProgress) {
            const percentDone = Math.round(100 * event.loaded / event.total);
            console.log(`File is ${percentDone}% loaded.`);
          } else if (event instanceof HttpResponse) {
            console.log('File is completely loaded!');
          }
        },
        (err) => {
          console.log("Upload Error:", err);
        }, () => {
          console.log("Upload done");
        }
      )
  }

6
Funziona bene con Angular6. Grazie. E hai bisogno di queste librerie per importare. import {HttpClient, HttpParams, HttpRequest, HttpEvent, HttpEventType, HttpResponse} da '@ angular / common / http';
Bharathiraja,

1
nel mio caso stavo usando il portatore di autorizzazione e ho aggiunto questo codice extralet params = new HttpParams(); let headers = new HttpHeaders({ 'Authorization': 'Bearer ' + localStorage.getItem('accessToken'), }); const options = { headers: headers, params: params, reportProgress: true, };
Ciprian Dragoe,

Vale la pena notare che le importazioni per Observablee HttpEventpotrebbero essere omesse del tutto se stai bene usando l'inferenza di tipo per fornire il tipo di ritorno della funzione per uploadFile()! this.http.request()restituisce già un tipo di Observable<HttpEvent<{}>>, quindi se si assegna alla richiesta un tipo generico (ovvero this.http.request<any>()l'intera funzione funziona correttamente con i tipi giusti.
wosevision,

2
La parte html va così input type="file" (change)="addFiles($event)" style="display: none" #file multiple> <button mat-raised-button color="primary" (click)="selectFile($event)">Upload File </button>
Shantam Mittal

22

Grazie a @Eswar. Questo codice ha funzionato perfettamente per me. Voglio aggiungere alcune cose alla soluzione:

Stavo ricevendo un errore: java.io.IOException: RESTEASY007550: Unable to get boundary for multipart

Per risolvere questo errore, è necessario rimuovere il "Tipo di contenuto" "multipart / form-data". Ha risolto il mio problema.


5
+1. Se rimuovi Content-Type, viene generato correttamente. Ad esempio: multipart/form-data; boundary=---------------------------186035562730765173675680113. Vedi anche stackoverflow.com/a/29697774/1475331 e github.com/angular/angular/issues/11819 .
turdus-merula,

1
Ricevo questo errore java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found"simile al tuo, tuttavia quando rimuovo l' Content-Typeintestazione ottengo invece un 404 dal backend. Stiamo usando Spring e Angular 2. Qualsiasi aiuto apprezzato.
Helen,

Questo dovrebbe essere solo un commento sulla sua risposta, no?
MMalke,

19

Poiché l'esempio di codice è un po 'obsoleto, ho pensato di condividere un approccio più recente, usando Angular 4.3 e la nuova (er) HttpClient API, @ angular / common / http

export class FileUpload {

@ViewChild('selectedFile') selectedFileEl;

uploadFile() {
let params = new HttpParams();

let formData = new FormData();
formData.append('upload', this.selectedFileEl.nativeElement.files[0])

const options = {
    headers: new HttpHeaders().set('Authorization', this.loopBackAuth.accessTokenId),
    params: params,
    reportProgress: true,
    withCredentials: true,
}

this.http.post('http://localhost:3000/api/FileUploads/fileupload', formData, options)
.subscribe(
    data => {
        console.log("Subscribe data", data);
    },
    (err: HttpErrorResponse) => {
        console.log(err.message, JSON.parse(err.error).error.message);
    }
)
.add(() => this.uploadBtn.nativeElement.disabled = false);//teardown
}

1
hai l'html per questo? Mi piace che questo stia usando HttpParams. Mi chiedo solo se hai un esempio di lavoro completo da qualche parte. Grazie
Maddy,

In questo modo come posso caricare più file insieme come un array? come dovrebbe essere aggiunto all'oggetto dati del modulo?
SSR

dai un'occhiata ai dati del modulo multipart webdavsystem.com/javaserver/doc/resumable_upload/multipart_post
jsaddwater

15

In Angular 2+, è molto importante lasciare vuoto Content-Type . Se imposti il ​​"Tipo di contenuto" su "multipart / form-data" il caricamento non funzionerà!

upload.component.html

<input type="file" (change)="fileChange($event)" name="file" />

upload.component.ts

export class UploadComponent implements OnInit {
    constructor(public http: Http) {}

    fileChange(event): void {
        const fileList: FileList = event.target.files;
        if (fileList.length > 0) {
            const file = fileList[0];

            const formData = new FormData();
            formData.append('file', file, file.name);

            const headers = new Headers();
            // It is very important to leave the Content-Type empty
            // do not use headers.append('Content-Type', 'multipart/form-data');
            headers.append('Authorization', 'Bearer ' + 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9....');
            const options = new RequestOptions({headers: headers});

            this.http.post('https://api.mysite.com/uploadfile', formData, options)
                 .map(res => res.json())
                 .catch(error => Observable.throw(error))
                 .subscribe(
                     data => console.log('success'),
                     error => console.log(error)
                 );
        }
    }
}


7

Questa semplice soluzione ha funzionato per me: file-upload.component.html

<div>
  <input type="file" #fileInput placeholder="Upload file..." />
  <button type="button" (click)="upload()">Upload</button>
</div>

E quindi eseguire il caricamento nel componente direttamente con XMLHttpRequest .

import { Component, OnInit, ViewChild } from '@angular/core';

@Component({
  selector: 'app-file-upload',
  templateUrl: './file-upload.component.html',
  styleUrls: ['./file-upload.component.css']
})
export class FileUploadComponent implements OnInit {

  @ViewChild('fileInput') fileInput;

  constructor() { }

  ngOnInit() {
  }

  private upload() {
    const fileBrowser = this.fileInput.nativeElement;
    if (fileBrowser.files && fileBrowser.files[0]) {
      const formData = new FormData();
      formData.append('files', fileBrowser.files[0]);
      const xhr = new XMLHttpRequest();
      xhr.open('POST', '/api/Data/UploadFiles', true);
      xhr.onload = function () {
        if (this['status'] === 200) {
            const responseText = this['responseText'];
            const files = JSON.parse(responseText);
            //todo: emit event
        } else {
          //todo: error handling
        }
      };
      xhr.send(formData);
    }
  }

}

Se si utilizza dotnet core, il nome del parametro deve corrispondere al nome del campo from. file in questo caso:

[HttpPost("[action]")]
public async Task<IList<FileDto>> UploadFiles(List<IFormFile> files)
{
  return await _binaryService.UploadFilesAsync(files);
}

Questa risposta è una piaga di http://blog.teamtreehouse.com/uploading-files-ajax

Modifica : dopo il caricamento, è necessario cancellare il caricamento del file in modo che l'utente possa selezionare un nuovo file. E invece di usare XMLHttpRequest, forse è meglio usare fetch:

private addFileInput() {
    const fileInputParentNative = this.fileInputParent.nativeElement;
    const oldFileInput = fileInputParentNative.querySelector('input');
    const newFileInput = document.createElement('input');
    newFileInput.type = 'file';
    newFileInput.multiple = true;
    newFileInput.name = 'fileInput';
    const uploadfiles = this.uploadFiles.bind(this);
    newFileInput.onchange = uploadfiles;
    oldFileInput.parentNode.replaceChild(newFileInput, oldFileInput);
  }

  private uploadFiles() {
    this.onUploadStarted.emit();
    const fileInputParentNative = this.fileInputParent.nativeElement;
    const fileInput = fileInputParentNative.querySelector('input');
    if (fileInput.files && fileInput.files.length > 0) {
      const formData = new FormData();
      for (let i = 0; i < fileInput.files.length; i++) {
        formData.append('files', fileInput.files[i]);
      }

      const onUploaded = this.onUploaded;
      const onError = this.onError;
      const addFileInput = this.addFileInput.bind(this);
      fetch('/api/Data/UploadFiles', {
        credentials: 'include',
        method: 'POST',
        body: formData,
      }).then((response: any) => {
        if (response.status !== 200) {
          const error = `An error occured. Status: ${response.status}`;
          throw new Error(error);
        }
        return response.json();
      }).then(files => {
        onUploaded.emit(files);
        addFileInput();
      }).catch((error) => {
        onError.emit(error);
      });
    }

https://github.com/yonexbat/cran/blob/master/cranangularclient/src/app/file-upload/file-upload.component.ts


3

Questo è un tutorial utile come caricare il file usando il caricamento di file ng2 e SENZA caricamento di file ng2.

Per me aiuta molto.

Al momento, il tutorial contiene un paio di errori:

1- Il client deve avere lo stesso URL di caricamento di un server, quindi nella app.component.tsriga di modifica

const URL = 'http://localhost:8000/api/upload';

per

const URL = 'http://localhost:3000';

2- Il server invia la risposta come 'text / html', quindi in app.component.tsmodifica

.post(URL, formData).map((res:Response) => res.json()).subscribe(
  //map the success function and alert the response
  (success) => {
    alert(success._body);
  },
  (error) => alert(error))

per

.post(URL, formData)  
.subscribe((success) => alert('success'), (error) => alert(error));

3

Per caricare l'immagine con i campi modulo

SaveFileWithData(article: ArticleModel,picture:File): Observable<ArticleModel> 
{

    let headers = new Headers();
    // headers.append('Content-Type', 'multipart/form-data');
    // headers.append('Accept', 'application/json');

let requestoptions = new RequestOptions({
  method: RequestMethod.Post,
  headers:headers
    });



let formData: FormData = new FormData();
if (picture != null || picture != undefined) {
  formData.append('files', picture, picture.name);
}
 formData.append("article",JSON.stringify(article));

return this.http.post("url",formData,requestoptions)
  .map((response: Response) => response.json() as ArticleModel);
} 

Nel mio caso avevo bisogno di .NET Web Api in C #

// POST: api/Articles
[ResponseType(typeof(Article))]
public async Task<IHttpActionResult> PostArticle()
{
    Article article = null;
    try
    {

        HttpPostedFile postedFile = null;
        var httpRequest = HttpContext.Current.Request;

        if (httpRequest.Files.Count == 1)
        {
            postedFile = httpRequest.Files[0];
            var filePath = HttpContext.Current.Server.MapPath("~/" + postedFile.FileName);
            postedFile.SaveAs(filePath);
        }
        var json = httpRequest.Form["article"];
         article = JsonConvert.DeserializeObject <Article>(json);

        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        article.CreatedDate = DateTime.Now;
        article.CreatedBy = "Abbas";

        db.articles.Add(article);
        await db.SaveChangesAsync();
    }
    catch (Exception ex)
    {
        int a = 0;
    }
    return CreatedAtRoute("DefaultApi", new { id = article.Id }, article);
}

3

Oggi sono stato integrato il pacchetto ng2-file-upload nella mia applicazione angolare 6, era abbastanza semplice, si prega di trovare il codice di alto livello di seguito.

importare il modulo di caricamento file ng2

app.module.ts

    import { FileUploadModule } from 'ng2-file-upload';

    ------
    ------
    imports:      [ FileUploadModule ],
    ------
    ------

FileUploader di importazione file ts componente

app.component.ts

    import { FileUploader, FileLikeObject } from 'ng2-file-upload';
    ------
    ------
    const URL = 'http://localhost:3000/fileupload/';
    ------
    ------

     public uploader: FileUploader = new FileUploader({
        url: URL,
        disableMultipart : false,
        autoUpload: true,
        method: 'post',
        itemAlias: 'attachment'

        });

      public onFileSelected(event: EventEmitter<File[]>) {
        const file: File = event[0];
        console.log(file);

      }
    ------
    ------

HTML componente aggiungere tag file

app.component.html

 <input type="file" #fileInput ng2FileSelect [uploader]="uploader" (onFileSelected)="onFileSelected($event)" />

Stackblitz online funzionante Link: https://ng2-file-upload-example.stackblitz.io

Esempio di codice Stackblitz: https://stackblitz.com/edit/ng2-file-upload-example

Link alla documentazione ufficiale https://valor-software.com/ng2-file-upload/


1

Prova a non impostare il optionsparametro

this.http.post(${this.apiEndPoint}, formData)

e assicurati di non impostare il globalHeaderstuo factory Http.


1

Nella forma più semplice, il seguente codice funziona in Angular 6/7

this.http.post("http://destinationurl.com/endpoint", fileFormData)
  .subscribe(response => {
    //handle response
  }, err => {
    //handle error
  });

Ecco l' implementazione completa


1

jspdf e Angular 8

Genero un pdf e voglio caricare il pdf con richiesta POST, ecco come faccio (Per chiarezza, elimino parte del codice e del livello di servizio)

import * as jsPDF from 'jspdf';
import { HttpClient } from '@angular/common/http';

constructor(private http: HttpClient)

upload() {
    const pdf = new jsPDF()
    const blob = pdf.output('blob')
    const formData = new FormData()
    formData.append('file', blob)
    this.http.post('http://your-hostname/api/upload', formData).subscribe()
}

0

Ho caricato il file usando il riferimento. Nessun pacchetto è richiesto per caricare il file in questo modo.

// codice da scrivere nel file .ts

@ViewChild("fileInput") fileInput;

addFile(): void {
let fi = this.fileInput.nativeElement;
if (fi.files && fi.files[0]) {
  let fileToUpload = fi.files[0];
    this.admin.addQuestionApi(fileToUpload)
      .subscribe(
        success => {
          this.loading = false;
          this.flashMessagesService.show('Uploaded successfully', {
            classes: ['alert', 'alert-success'],
            timeout: 1000,
          });
        },
        error => {
          this.loading = false;
          if(error.statusCode==401) this.router.navigate(['']);
          else
            this.flashMessagesService.show(error.message, {
              classes: ['alert', 'alert-danger'],
              timeout: 1000,
            });
        });
  }

}

// codice da scrivere nel file service.ts

addQuestionApi(fileToUpload: any){
var headers = this.getHeadersForMultipart();
let input = new FormData();
input.append("file", fileToUpload);

return this.http.post(this.baseUrl+'addQuestions', input, {headers:headers})
      .map(response => response.json())
      .catch(this.errorHandler);

}

// codice da scrivere in html

<input type="file" #fileInput>
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.