Datei-Upload im Winkel?

173

Ich weiß, dass dies eine sehr allgemeine Frage ist, aber ich kann keine Datei in Angular 2 hochladen. Ich habe es versucht

1) http://valor-software.com/ng2-file-upload/ und

2) http://ng2-uploader.com/home

...aber scheiterte. Hat jemand eine Datei in Angular hochgeladen? Welche Methode haben Sie angewendet? Wie geht das? Wenn ein Beispielcode oder ein Demo-Link bereitgestellt wird, wird dies sehr geschätzt.

heman123
quelle

Antworten:

375

Angular 2 bietet eine gute Unterstützung für das Hochladen von Dateien. Es ist keine Bibliothek eines Drittanbieters erforderlich.

<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)
            )
    }
}

using @ angle / core ":" ~ 2.0.0 "und @ angle / http:" ~ 2.0.0 "

Eswar
quelle
5
Zumindest in meinem Fall funktioniert es nicht. sailsJs Server erhalten leere Datei Array / Objekt
Kaleem Ullah
20
Es funktionierte für mich außer - ich musste an dieser Zeile arbeiten - headers.append('enctype', 'multipart/form-data');(benutzte 'enctype', um 'Content-Type' zu ersetzen). Vielleicht hängt es vom serverseitigen Code ab. (dh api)
Ariful Islam
29
Seien Sie großartig, wenn das Angular-Team eine Dokumentation zu diesem Thema schreiben würde. Ich kann keine einzige Zeile darüber in den Dokumenten finden. Dieses Codebeispiel ist veraltet und funktioniert nicht mit v4 +.
Rob B
10
Hinweis: Bei einigen Anwendungsservern wird das Festlegen des Inhaltstyps abgelehnt. Sie müssen es leer lassen: let headers = new Headers (); Der Browser erledigt alles für Sie.
PeterS
6
LMFAO kämpfte 20 Minuten mit diesem Mist, bis mir klar wurde, dass ich die Header überhaupt nicht setzen musste. Hinweis für andere, die Angular 4.xx mit .Net Webapi verwenden, versuchen Sie nicht, die Header festzulegen! Vielen Dank für den Hinweis, dass @PeterS
Jota.Toledo
76

Aus den obigen Antworten baue ich dies mit Angular 5.x.

Rufen Sie einfach uploadFile(url, file).subscribe()an, um einen Upload auszulösen

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);
  }
}

Verwenden Sie es so in Ihrer Komponente

  // 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");
        }
      )
  }
Tarion
quelle
6
Funktioniert gut mit Angular6. Danke dir. Und Sie benötigen diese Bibliotheken zum Importieren. {HttpClient, HttpParams, HttpRequest, HttpEvent, HttpEventType, HttpResponse} aus '@ angle / common / http' importieren;
Bharathiraja
1
In meinem Fall habe ich den Autorisierungsträger verwendet und diesen zusätzlichen Code hinzugefügtlet params = new HttpParams(); let headers = new HttpHeaders({ 'Authorization': 'Bearer ' + localStorage.getItem('accessToken'), }); const options = { headers: headers, params: params, reportProgress: true, };
Ciprian Dragoe
Es ist erwähnenswert, dass die Importe für Observableund HttpEventvollständig weggelassen werden könnten, wenn Sie die Typinferenz verwenden können, um den Rückgabetyp der Funktion für bereitzustellen uploadFile()! this.http.request()gibt bereits einen Typ von zurück Observable<HttpEvent<{}>>, also wenn Sie dem Anforderungsaufruf einen generischen Typ geben (dh this.http.request<any>()dann funktioniert die gesamte Funktion nur mit den richtigen Typen.
wosevision
2
Der HTML-Teil geht so 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

Danke an @Eswar. Dieser Code hat bei mir perfekt funktioniert. Ich möchte der Lösung bestimmte Dinge hinzufügen:

Ich habe eine Fehlermeldung erhalten: java.io.IOException: RESTEASY007550: Unable to get boundary for multipart

Um diesen Fehler zu beheben, sollten Sie den "Inhaltstyp" "Multipart / Formulardaten" entfernen. Es hat mein Problem gelöst.

heman123
quelle
5
+1. Wenn Sie den Inhaltstyp entfernen, wird er korrekt generiert. ZB : multipart/form-data; boundary=---------------------------186035562730765173675680113. Siehe auch stackoverflow.com/a/29697774/1475331 und github.com/angular/angular/issues/11819 .
Turdus-Merula
1
Ich erhalte diesen Fehler, java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found"der Ihrem ähnlich ist. Wenn ich jedoch den Content-TypeHeader entferne, erhalte ich stattdessen einen 404 aus dem Backend. Wir verwenden Spring und Angular 2. Jede Hilfe wird geschätzt.
Helen
Dies sollte nur ein Kommentar zu seiner Antwort sein, nicht wahr?
MMalke
19

Da das Codebeispiel etwas veraltet ist, dachte ich, ich würde einen neueren Ansatz mit Angular 4.3 und der neuen (er) HttpClient-API @ angle / common / http teilen

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
}
jsaddwater
quelle
1
Hast du das HTML dafür? Ich mag, dass dies HttpParams verwendet. Ich frage mich nur, ob Sie irgendwo ein vollständiges Arbeitsbeispiel haben. Vielen Dank
Maddy
Wie kann ich auf diese Weise mehrere Dateien zusammen als Array hochladen? Wie soll es an das Formulardatenobjekt angehängt werden?
SSR
Werfen
Sie
15

In Angular 2+ ist es sehr wichtig , den Inhaltstyp leer zu lassen. Wenn Sie den 'Content-Type' auf 'multipart / form-data' setzen, funktioniert der Upload nicht!

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)
                 );
        }
    }
}
abahet
quelle
8

Ich habe das folgende Werkzeug aus der Grundierung mit Erfolg verwendet. Ich habe keine Haut im Spiel mit primeNg, ich gebe nur meinen Vorschlag weiter.

http://www.primefaces.org/primeng/#/fileupload

John Baird
quelle
Können Sie uns bitte mitteilen, ob dies NG2-kompatibel ist?
G1P
@ G1P Es ist Angular 4 sicher kompatibel. primefaces.org/primeng/#/setup
makkasi
7

Diese einfache Lösung hat bei mir funktioniert: file-upload.component.html

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

Führen Sie dann den Upload in der Komponente direkt mit XMLHttpRequest durch .

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);
    }
  }

}

Wenn Sie den Dotnet-Kern verwenden, muss der Parametername mit dem Absendernamen übereinstimmen. Dateien in diesem Fall:

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

Diese Antwort ist ein Plagiat von http://blog.teamtreehouse.com/uploading-files-ajax

Bearbeiten : Nach dem Hochladen müssen Sie den Datei-Upload löschen, damit der Benutzer eine neue Datei auswählen kann. Und anstatt XMLHttpRequest zu verwenden, ist es vielleicht besser, fetch zu verwenden:

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

yonexbat
quelle
3

Dies ist ein nützliches Tutorial zum Hochladen von Dateien mit dem ng2-Datei-Upload und OHNE ng2-Datei-Upload.

Für mich hilft es sehr.

Im Moment enthält das Tutorial einige Fehler:

1- Der Client sollte dieselbe Upload-URL wie ein Server haben, also in der app.component.tsÄnderungszeile

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

zu

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

2- Server senden Antwort als 'Text / HTML', also in app.component.tsÄnderung

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

zu

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

Hochladen von Bildern mit Formularfeldern

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);
} 

In meinem Fall brauchte ich .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);
}
Charlie
quelle
3

Heute wurde mir das ng2-Datei-Upload- Paket in meine Angular 6-Anwendung integriert. Es war ziemlich einfach. Bitte finden Sie den folgenden allgemeinen Code.

Importieren Sie das ng2-Datei-Upload- Modul

app.module.ts

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

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

Komponente ts Datei importieren FileUploader

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);

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

Komponenten-HTML-Tag zum Hinzufügen von Dateien

app.component.html

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

Working Online stackblitz Link: https://ng2-file-upload-example.stackblitz.io

Beispiel für einen Stackblitz-Code: https://stackblitz.com/edit/ng2-file-upload-example

Offizieller Dokumentationslink https://valor-software.com/ng2-file-upload/

Raja Rama Mohan Thavalam
quelle
1

Versuchen Sie, den optionsParameter nicht einzustellen

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

und stellen Sie sicher, dass Sie das nicht globalHeadersin Ihrer HTTP-Fabrik einstellen .

thxmxx
quelle
1

In der einfachsten Form funktioniert der folgende Code in Angular 6/7

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

Hier ist die komplette Implementierung

shaheer shukur
quelle
1

jspdf und Angular 8

Ich erstelle ein PDF und möchte das PDF mit POST-Anfrage hochladen. So gehe ich vor (Aus Gründen der Übersichtlichkeit lösche ich einen Teil der Code- und Serviceschicht).

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()
}
Brady Huang
quelle
0

Ich habe eine Datei mit Referenz hochgeladen. Zum Hochladen der Datei auf diese Weise ist kein Paket erforderlich.

// Code, der in die .ts-Datei geschrieben werden soll

@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,
            });
        });
  }

}}

// Code, der in die Datei service.ts geschrieben werden soll

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);

}}

// Code, der in HTML geschrieben werden soll

<input type="file" #fileInput>
Sheena Singla
quelle