Tải lên tập tin trong góc?


173

Tôi biết đây là một câu hỏi chung chung nhưng tôi không tải lên được tệp trong Angular 2. Tôi đã thử

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

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

...nhưng không thành công. Có ai đã tải lên một tập tin trong Angular? Bạn đã sử dụng phương pháp nào? Làm thế nào để làm như vậy? Nếu bất kỳ mã mẫu hoặc liên kết demo được cung cấp, nó sẽ thực sự được đánh giá cao.

Câu trả lời:


375

Angular 2 cung cấp hỗ trợ tốt để tải lên các tập tin. Không có thư viện bên thứ ba được yêu cầu.

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

sử dụng @ angular / core ":" ~ 2.0.0 "và @ angular / http:" ~ 2.0.0 "


5
nó không hoạt động, ít nhất là trong trường hợp của tôi Máy chủ sailsJs nhận được mảng / đối tượng tệp trống
Kaleem Ullah

20
Nó hoạt động với tôi ngoại trừ - tôi phải làm việc trên dòng này- headers.append('enctype', 'multipart/form-data');(được sử dụng 'enctype' để thay thế 'Loại nội dung'). Có lẽ nó phụ thuộc vào mã phía máy chủ. (tức là api)
Hồi giáo Ariful

29
Thật tuyệt nếu nhóm Angular sẽ viết một số tài liệu về chủ đề này, tôi không thể tìm thấy một dòng nào về nó trong tài liệu của họ. Mẫu mã này đã hết hạn và không hoạt động với v4 +.
Cướp B

10
Lưu ý đối với một số máy chủ ứng dụng, cài đặt loại nội dung sẽ bị từ chối. Bạn cần để trống: let headers = new Headers (); Trình duyệt sẽ sắp xếp tất cả cho bạn.
PeterS

6
LMFAO đã vật lộn 20 phút với thứ nhảm nhí này cho đến khi tôi nhận ra rằng tôi không cần thiết phải đặt tiêu đề. Lưu ý cho những người khác sử dụng 4.xx góc với .Net webapi, đừng cố thiết lập các tiêu đề! Thx đã chỉ ra rằng @PeterS
Jota.Toledo

76

Từ các câu trả lời ở trên, tôi xây dựng điều này với Angular 5.x

Chỉ cần gọi uploadFile(url, file).subscribe()để kích hoạt tải lên

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

Sử dụng nó như thế này trong thành phần của bạn

  // 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
Hoạt động tốt với Angular6. Cảm ơn bạn. Và bạn cần những thư viện này để nhập khẩu. nhập {httpClient, HttpParams, HttpRequest, HttpEvent, HttpEventType, HttpResponse} từ '@ angular / common / http';
Bharathiraja

1
trong trường hợp của tôi, tôi đã sử dụng người ủy quyền và thêm mã bổ sung nàylet params = new HttpParams(); let headers = new HttpHeaders({ 'Authorization': 'Bearer ' + localStorage.getItem('accessToken'), }); const options = { headers: headers, params: params, reportProgress: true, };
Ciprian Dragoe

Cần lưu ý rằng việc nhập ObservableHttpEventcó thể được bỏ qua hoàn toàn nếu bạn ổn với việc sử dụng suy luận kiểu để cung cấp kiểu trả về của hàm cho uploadFile()! this.http.request()đã trả về một loại Observable<HttpEvent<{}>>, vì vậy nếu bạn đưa ra yêu cầu hãy gọi một loại chung (nghĩa là this.http.request<any>()toàn bộ chức năng chỉ hoạt động với đúng loại.
wosevision

2
Phần html diễn ra như thế này input type="file" (change)="addFiles($event)" style="display: none" #file multiple> <button mat-raised-button color="primary" (click)="selectFile($event)">Upload File </button>
Chaiam Găngal

22

Cảm ơn @Eswar. Mã này làm việc hoàn hảo cho tôi. Tôi muốn thêm một số điều vào giải pháp:

Tôi đã nhận được lỗi: java.io.IOException: RESTEASY007550: Unable to get boundary for multipart

Để giải quyết lỗi này, bạn nên xóa "Kiểu nhiều nội dung" "nhiều dữ liệu / biểu mẫu dữ liệu". Nó giải quyết vấn đề của tôi.


5
+1. Nếu bạn loại bỏ Content-Type, nó sẽ được tạo chính xác. Vd : multipart/form-data; boundary=---------------------------186035562730765173675680113. Đồng thời xem stackoverflow.com/a/29697774/1485331github.com/angular/angular/issues/11819 .
turdus-merula

1
Tôi đang gặp lỗi java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found"này tương tự như lỗi của bạn, tuy nhiên khi tôi xóa Content-Typetiêu đề, tôi nhận được 404 từ phần phụ trợ thay thế. Chúng tôi đang sử dụng Spring và Angular 2. Bất kỳ trợ giúp nào cũng được đánh giá cao.
Helen

Đây chỉ là một nhận xét về câu trả lời của anh ấy, phải không?
MMalke

19

Vì mẫu mã hơi lỗi thời, tôi nghĩ rằng tôi sẽ chia sẻ một cách tiếp cận gần đây hơn, sử dụng Angular 4.3 và API httpClient (er) mới, @ 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
Bạn có html cho cái này không? Tôi thích điều này là sử dụng HttpParams. Chỉ cần tự hỏi nếu bạn có một ví dụ làm việc hoàn chỉnh ở đâu đó. Cảm ơn
Maddy

Theo cách này, làm thế nào tôi có thể tải lên nhiều tệp với nhau như một mảng? Làm thế nào nó nên nối vào đối tượng dữ liệu biểu mẫu?
SSR

hãy xem dữ liệu biểu mẫu nhiều trang webdavsystem.com/javaserver/doc/resumable_upload/multipart_post
jsaddwater

15

Trong Angular 2+, điều rất quan trọng là để trống Kiểu nội dung . Nếu bạn đặt 'Loại nội dung' thành 'nhiều dữ liệu / biểu mẫu dữ liệu' thì việc tải lên sẽ không hoạt động!

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

Giải pháp đơn giản này hiệu quả với tôi: file-upload.component.html

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

Và sau đó thực hiện tải lên trong thành phần trực tiếp với 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);
    }
  }

}

Nếu bạn đang sử dụng lõi dotnet, tên tham số phải khớp với tên từ trường. tập tin trong trường hợp này:

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

Câu trả lời này là một tai họa của http://blog.teamtreehouse.com/uploading-files-ajax

Chỉnh sửa : Sau khi tải lên, bạn phải xóa tệp tải lên để người dùng có thể chọn một tệp mới. Và thay vì sử dụng XMLHttpRequest, có lẽ tốt hơn là sử dụng tìm nạp:

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

Đây là hướng dẫn hữu ích , cách tải tệp lên bằng cách sử dụng tệp tải lên ng2 và KHÔNG CÓ ng2-tệp-tải lên.

Đối với tôi nó giúp rất nhiều.

Hiện tại, hướng dẫn có một vài lỗi:

1- Máy khách phải có cùng một url tải lên như một máy chủ, vì vậy trong app.component.tsdòng thay đổi

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

đến

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

2- Máy chủ gửi phản hồi dưới dạng 'văn bản / html', do đó, app.component.tsthay đổi

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

đến

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

3

Để tải lên hình ảnh với các trường mẫu

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

Trong trường hợp của tôi, tôi cần .NET Web Api trong 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

Hôm nay tôi đã được tích hợp gói tải lên ng2 vào ứng dụng 6 góc của mình. Nó khá đơn giản, Vui lòng tìm mã cấp cao bên dưới.

nhập mô-đun ng2-file-upload

app.module.ts

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

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

Thành phần nhập tệp ts 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);

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

Thành phần HTML thêm thẻ tập tin

app.component.html

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

Liên kết stackblitz trực tuyến làm việc: https://ng2-file-upload-example.stackblitz.io

Ví dụ về mã Stackblitz: https://stackblitz.com/edit/ng2-file-upload-example

Liên kết tài liệu chính thức https://valor-software.com/ng2-file-upload/


1

Cố gắng không thiết lập optionstham số

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

và đảm bảo rằng bạn không thiết lập globalHeaderstrong nhà máy http của mình.


1

Ở dạng đơn giản nhất, đoạn mã sau hoạt động trong Angular 6/7

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

Đây là thực hiện đầy đủ


1

jspdf và góc 8

Tôi tạo pdf và muốn tải lên pdf với yêu cầu POST, đây là cách tôi làm (Để rõ ràng, tôi xóa một số mã và lớp dịch vụ)

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

Tôi đã tải lên tệp bằng cách sử dụng tài liệu tham khảo. Không có gói được yêu cầu để tải lên tập tin theo cách này.

// mã được ghi trong tệp .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,
            });
        });
  }

}

// mã được ghi trong tệp 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);

}

// mã được viết bằng html

<input type="file" #fileInput>
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.