How to upload file in Angular2
Asked Answered
H

4

40

I have to submit a form along with image. i have tried this code (with multiple ways) but did't work for me. is there anyone having working demo of file uploading using angular2 please help me out.

component.html

    <form class="form-horizontal" role="form" >

        <div class="form-group">
            <label class="control-label col-sm-4" for="myname" style="">Name<span class="asterisk">*</span></label>
            <div class="col-sm-7">
                <div>
                    <input type="text" class="form-control" id="myname"
                    [(ngModel)]="myfile.name">                        
                </div>                  
            </div>                               
        </div>        


        <div class="form-group">
            <label class="control-label col-sm-4" for="myimage">Image</label>
            <div class="col-sm-7">
                <div>
                    <input type="file" (change)="fileChangeEvent($event)" placeholder="Upload file..." />                         
                </div>   
            </div>
        </div>


        <div class="form-group">        
        <div class="text-center">
            <button type="button" (click)="upload()">Upload</button>             
        </div>
        </div>
  </form>

component.ts

     myfile={
                "name":"Mubashshir",               
                "image":''
     }

     fileChangeEvent(fileInput: any){
        this.myfile.image = fileInput.target.files;        
     }

     upload(){
          this.base_path_service.PostRequest('http://128.199.190.109/api/school/schoolDetail/',this.myfile)
            .subscribe(
                data => {
                            console.log("data submitted");                        
                        },
                err => console.log(err),
                () =>{
                     console.log('Authentication Complete');                    

                }
            );
      }
Haupt answered 14/3, 2016 at 10:43 Comment(1)
B
27

In fact, the Http class doesn't support that at the moment.

You need to leverage the underlying XHR object to do that:

import {Injectable} from 'angular2/core';
import {Observable} from 'rxjs/Rx';

@Injectable()
export class UploadService {
  constructor () {
    this.progress$ = Observable.create(observer => {
      this.progressObserver = observer
    }).share();
  }

  private makeFileRequest (url: string, params: string[], files: File[]): Observable {
    return Observable.create(observer => {
      let formData: FormData = new FormData(),
        xhr: XMLHttpRequest = new XMLHttpRequest();

      for (let i = 0; i < files.length; i++) {
        formData.append("uploads[]", files[i], files[i].name);
      }

      xhr.onreadystatechange = () => {
        if (xhr.readyState === 4) {
          if (xhr.status === 200) {
            observer.next(JSON.parse(xhr.response));
            observer.complete();
          } else {
            observer.error(xhr.response);
          }
        }
      };

      xhr.upload.onprogress = (event) => {
        this.progress = Math.round(event.loaded / event.total * 100);

        this.progressObserver.next(this.progress);
      };

      xhr.open('POST', url, true);
      xhr.send(formData);
    });
  }
}

See this plunkr for more details: https://plnkr.co/edit/ozZqbxIorjQW15BrDFrg?p=info.

There is a an issue and a pending PR regarding this in the Angular repo:

Betweentimes answered 14/3, 2016 at 10:49 Comment(3)
How can you get the response from this? And shouldn't it be a Promise instead of an Observable now?Hube
Hey, im getting parse erros with this answer. EXCEPTION: SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON datavendor.js:1617 EXCEPTION: SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON datavendor.js:1617:2286 STACKTRACE:vendor.js:1617:2286 ................ Anyone else getting this problem ?Sophisticate
In the final release of angular you no longer need to mess with the underlying XHR object anymore, see this answer: https://mcmap.net/q/219927/-file-upload-with-angular2-to-rest-apiCornwallis
K
17

your http service file:

import { Injectable } from "@angular/core";
import { ActivatedRoute, Router } from '@angular/router';
import { Http, Headers, Response, Request, RequestMethod, URLSearchParams, RequestOptions } from "@angular/http";
import {Observable} from 'rxjs/Rx';
import { Constants } from './constants';
declare var $: any;

@Injectable()
export class HttpClient {
  requestUrl: string;
  responseData: any;
  handleError: any;

  constructor(private router: Router, 
  private http: Http, 
  private constants: Constants, 
  ) {
    this.http = http;
  }

  postWithFile (url: string, postData: any, files: File[]) {

    let headers = new Headers();
    let formData:FormData = new FormData();
    formData.append('files', files[0], files[0].name);
    // For multiple files
    // for (let i = 0; i < files.length; i++) {
    //     formData.append(`files[]`, files[i], files[i].name);
    // }

    if(postData !=="" && postData !== undefined && postData !==null){
      for (var property in postData) {
          if (postData.hasOwnProperty(property)) {
              formData.append(property, postData[property]);
          }
      }
    }
    var returnReponse = new Promise((resolve, reject) => {
      this.http.post(this.constants.root_dir + url, formData, {
        headers: headers
      }).subscribe(
          res => {
            this.responseData = res.json();
            resolve(this.responseData);
          },
          error => {
            this.router.navigate(['/login']);
            reject(error);
          }
      );
    });
    return returnReponse;
  }
}

call your function (Component file):

onChange(event) {
    let file = event.srcElement.files;
    let postData = {field1:"field1", field2:"field2"}; // Put your form data variable. This is only example.
    this._service.postWithFile(this.baseUrl + "add-update",postData,file).then(result => {
        console.log(result);
    });
}

your html code:

<input type="file" class="form-control" name="documents" (change)="onChange($event)" [(ngModel)]="stock.documents" #documents="ngModel">
Kyne answered 14/11, 2016 at 18:2 Comment(1)
This would not work, as http post does not support FormData, your data would not be passed to the server, github.com/angular/angular/issues/13241Immesh
O
3

Improved onChange() method :

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);
    }
Obverse answered 4/1, 2017 at 13:54 Comment(1)
Finally, I got a file object!!Wolcott
B
0

Here is the Angular 2 version

We needed to implement drag drop file input feature in one of our Angular 2 app.

We selected ng-file-upload for this.

We tried to follow the help page. As suggested, implemented drag-upload-input.html & drag-upload-input.component.ts like the following:

drag-upload-input.html

<!-- we only need single file upload -->
<input type="file" ng2FileSelect [uploader]="uploader" />

drag-upload-input.component.ts

import { Component } from '@angular/core';
import { FileUploader } from 'ng2-file-upload';

// const URL = '/api/';
const URL = 'https://evening-anchorage-3159.herokuapp.com/api/';

@Component({
  moduleId: module.id,
  selector: 'drag-upload-input',
  templateUrl: './drag-upload-input.html'
})
export class DragUploadInput {
  public uploader: FileUploader = new FileUploader({ url: URL });
  public hasBaseDropZoneOver: boolean = false;
  public hasAnotherDropZoneOver: boolean = false;

  public fileOverBase(e: any): void {
    this.hasBaseDropZoneOver = e;
  }

  public fileOverAnother(e: any): void {
    this.hasAnotherDropZoneOver = e;
  }
}

The app.module.ts has got FileUploadModule like this:

// File upload modules
import { FileUploadModule } from 'ng2-file-upload';
import { DragUploadInput } from './file-upload/drag-upload-input.component';

//other imports

@NgModule({
  imports: [ ... other imports
FileUploadModule
],
  declarations: [  ... other declarations
DragUploadInput],
  bootstrap: [AppComponent]
})
export class AppModule { }

And the systemjs.config.js looks like this:

(function (global) {
  System.config({
    // map tells the System loader where to look for things
    map: {
      // other libraries
      'ng2-file-upload': 'node_modules/ng2-file-upload',
    },
    packages: {
      // other packages
      ng2-file-upload': {
        main: 'ng2-file-upload.js',
        defaultExtension: 'js'
      }
    }
  });
})(this);

source

Bismuth answered 8/6, 2017 at 10:12 Comment(1)
hey, where the file uploaded to? How can we configure it?Collector

© 2022 - 2024 — McMap. All rights reserved.