Завантаження файлу кутовим?


173

Я знаю, що це дуже загальне питання, але мені не вдалося завантажити файл у кутовій формі 2. Я спробував

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

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

... але не вдалося. Хтось завантажив файл у Angular? Який метод ви використовували? Як це зробити? Якщо надано будь-який зразок коду чи демо-посилання, він буде дуже вдячний.

Відповіді:


375

Angular 2 забезпечує гарну підтримку для завантаження файлів. Бібліотека сторонньої сторони не потрібна.

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

використовуючи @ angular / core ":" ~ 2.0.0 "та @ angular / http:" ~ 2.0.0 "


5
це не працює, принаймні в моєму випадку. сервер sailsJs отримує порожній файловий масив / об’єкт
Kaleem Ullah

20
Це працювало для мене, за винятком - мені довелося працювати над цим headers.append('enctype', 'multipart/form-data');рядком (використовувався 'enctype', щоб замінити 'Content-Type'). Можливо, це залежить від коду на стороні сервера. (тобто api)
Ariful Islam

29
Будь чудовим, якщо команда Angular написала б якусь документацію з цього питання, я не можу знайти жодного рядка про це у своїх документах. Цей зразок коду застарілий і не працює з v4 +.
Роб Б

10
Зауважте, що для деяких серверів додатків налаштування типу вмісту буде відхилено. Потрібно, щоб це було порожнім: нехай заголовки = нові заголовки (); Веб-переглядач розбере все для вас.
PeterS

6
LMFAO боровся 20 хв з цим лаєм, поки не зрозумів, що мені взагалі не потрібно встановлювати заголовки. Зверніть увагу на інших, які використовують кутовий 4.xx за допомогою .Net webapi, не намагайтеся встановлювати заголовки! Thx для вказівки на це @PeterS
Jota.Toledo

76

З вищенаведених відповідей я будую це за допомогою кутового 5.x

Просто зателефонуйте, uploadFile(url, file).subscribe()щоб запустити завантаження

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

Використовуйте його так у своєму компоненті

  // 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
Чудово працює з Angular6. Дякую. І вам потрібні ці бібліотеки для імпорту. імпортувати {HttpClient, HttpParams, HttpRequest, HttpEvent, HttpEventType, HttpResponse} з '@ angular / common / http';
Bharathiraja

1
у моєму випадку я користувався носієм авторизації та додав цей додатковий кодlet params = new HttpParams(); let headers = new HttpHeaders({ 'Authorization': 'Bearer ' + localStorage.getItem('accessToken'), }); const options = { headers: headers, params: params, reportProgress: true, };
Ciprian Dragoe

Варто зазначити, що імпорт для Observableта HttpEventможе бути повністю пропущений, якщо ви добре використовуєте умовивід, щоб забезпечити тип повернення функції uploadFile()! this.http.request()вже повертає тип Observable<HttpEvent<{}>>, тому якщо ви даєте запит, викличте загальний тип (тобто this.http.request<any>()тоді вся функція просто працює з правильними типами.
wosevision

2
Частина html йде так 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

Завдяки @Eswar. Цей код прекрасно працював для мене. Я хочу додати в рішення певні речі:

Я отримував помилку: java.io.IOException: RESTEASY007550: Unable to get boundary for multipart

Для того, щоб вирішити цю помилку, слід видалити багаточастинні / форми-дані "Вміст-Тип". Це вирішило мою проблему.


5
+1. Якщо ви видалите Content-Type, він генерується правильно. Наприклад: multipart/form-data; boundary=---------------------------186035562730765173675680113. Також см stackoverflow.com/a/29697774/1475331 і github.com/angular/angular/issues/11819 .
turdus-merula

1
Я отримую цю помилку java.io.IOException: org.apache.tomcat.util.http.fileupload.FileUploadException: the request was rejected because no multipart boundary was found", схожу на вашу, однак, коли я видаляю Content-Typeзаголовок, натомість я отримую 404. Ми використовуємо Spring and Angular 2. Будь-яка допомога вдячна.
Олена

Це має бути лише коментарем до його відповіді, чи не так?
MMalke

19

Оскільки зразок коду трохи застарів, я подумав, що поділюсь останнім підходом, використовуючи Angular 4.3 та новий (er) API HttpClient, @ 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
у вас є HTML для цього? Мені подобається, що для цього використовується HttpParams. Просто цікаво, чи є у вас десь повний робочий приклад. Спасибі
Медді

Таким чином, як я можу завантажувати декілька файлів разом як масив? як він повинен додаватися до об’єкта даних форми?
ССР

подивіться дані багаточастинкових форм webdavsystem.com/javaserver/doc/resumable_upload/multipart_post
jsaddwater

15

У Angular 2+ дуже важливо залишити Тип вмісту порожнім. Якщо ви встановите "Тип вмісту" на "багаточастинні / форми-дані", завантаження не працюватиме!

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

8

Я використовував наступний інструмент для грунтування з успіхом. У мене немає гри в PrimeNg, просто передаю свою пропозицію.

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


Будь ласка, чи можете ви повідомити нас, чи це сумісний NG2 ??
G1P

@ G1P Це кутовий 4 напевно сумісний. primefaces.org/primeng/#/setup
makkasi

7

Це просте рішення працювало для мене: file-upload.component.html

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

А потім виконайте завантаження в компоненті безпосередньо за допомогою 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);
    }
  }

}

Якщо ви використовуєте ядро ​​dotnet, ім'я параметра повинно відповідати імені поля. файли в цьому випадку:

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

Ця відповідь є плагіатом http://blog.teamtreehouse.com/uploading-files-ajax

Редагувати : Після завантаження потрібно очистити завантаження файлу, щоб користувач міг вибрати новий файл. І замість того, щоб використовувати XMLHttpRequest, можливо, краще використовувати 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

Це корисний підручник , як завантажувати файл за допомогою файлу ng2-upload та БЕЗ ng2-file-upload.

Для мене це дуже допомагає.

На даний момент підручник містить пару помилок:

1- Клієнт повинен мати такий самий URL-адресу завантаження, як і сервер, тому в app.component.tsрядку зміни

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

до

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

2- Сервер надсилає відповідь як "текст / html", так що app.component.tsзмінюється

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

до

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

3

Завантажити зображення з полями форми

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

У моєму випадку мені знадобився .NET Web Api в 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

Сьогодні мені було інтегровано пакет для завантаження файлів ng2-файл у мою програму з 6-ти кутом. Це було досить просто. Будь ласка, знайдіть нижче код високого рівня.

імпортувати модуль завантаження файлів ng2

app.module.ts

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

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

Компонент імпорту файла файлів 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);

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

Компонент HTML тег додавання файлу

app.component.html

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

Робота в мережі stackblitz Посилання: https://ng2-file-upload-example.stackblitz.io

Приклад Stackblitz: https://stackblitz.com/edit/ng2-file-upload-example

Офіційне посилання на документацію https://valor-software.com/ng2-file-upload/


1

Спробуйте не встановити optionsпараметр

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

і переконайтеся, що ви не встановлюєте на globalHeadersсвоєму Http заводі.



1

jspdf та Angular 8

Я генерую pdf і хочу завантажувати pdf із запитом POST, так це роблю (для наочності я видаляю частину коду та рівня обслуговування)

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

Я завантажую файл за допомогою посилання. Для завантаження файлу таким чином не потрібен пакет.

// код, який потрібно записати у .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,
            });
        });
  }

}

// код, який потрібно записати у файл 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);

}

// код, який потрібно записати в html

<input type="file" #fileInput>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.