Reputation: 1103
I have an Ionic 2 PWA, so it should run in the browser. I want that the user can upload a file to the server. Because the file chooser from ionic native is only for android, I can't use it in browser. So my idea was to use an input field with type="file". But my problem is, that I'm only getting the file name and not the path. And to upload the file I need the path. At first I have tried it with ngModel and then with the form builder from ionic. This is my code with the form builder:
TS:
import {Component} from '@angular/core';
import {Validators, FormBuilder, FormGroup } from '@angular/forms';
@Component({
selector: 'page-test',
templateUrl: 'test.html',
})
export class TestPage {
private file : FormGroup;
constructor( private formBuilder: FormBuilder ) {
this.file = this.formBuilder.group({
image: ['']
});
}
logForm(){
console.log(this.file.value)
}
}
HTML:
...
<ion-content padding>
<form [formGroup]="file" (ngSubmit)="logForm()">
<input type="file" size="50" formControlName="image">
<button ion-button type="submit">Submit</button>
</form>
</ion-content>
But like I said, the console only logs the filename:
Object { image: "2970.jpg" }
And if I log "this.file" (without .value) I find there neither a file object or something like this. Is there a way to get the file path in an ionic browser app to upload it to a server?
Upvotes: 3
Views: 2550
Reputation: 911
I don't know if you already found a solution but I will publish it anyway...
For this solution you don't need any external npm module. Here is step-by-step
Create new component by running
$ ionic generate component file-uploader
Then copy and paste the code below
src/components/file-uploader/file-uploader.ts
import { Component, ViewChild, ElementRef, Input } from '@angular/core';
import 'rxjs/add/operator/map';
import { Observable } from 'rxjs/Observable';
import { HttpClient } from '@angular/common/http';
/**
* Usage
*
* <file-uploader [apiUrl]="apiUrl" [params]="uploadParams"></file-uploader>
*
* <file-uploader [apiUrl]="apiUrl" [params]="[{'key':'language_code', 'value': 'en'}]"></file-uploader>
*
*/
@Component({
selector: 'file-uploader',
templateUrl: 'file-uploader.html'
})
export class FileUploaderComponent
{
@ViewChild('file') fileInput: ElementRef;
@Input('apiUrl') apiUrl: string = null;
@Input('params') params: Array<{key: string, value: string}> = [];
@Input('buttonText') buttonText: string = 'Upload';
@Input('buttonType') buttonType: 'button' | 'icon' = 'icon';
@Input('icon') icon: string = 'cloud-upload';
@Input('onUploadSuccess') onUploadSuccess: (file: File, response: any) => void
= function (file: File, response: any) { console.log(file); console.log(response); };
@Input('onUploadError') onUploadError: (file: File) => void = function (error: any) { console.log(error) };
fileToUpload: File = null;
constructor(private httpClient: HttpClient)
{
}
triggerFileInputClick()
{
this.fileInput.nativeElement.click();
}
onFileInputChange(files: FileList)
{
this.fileToUpload = files.item(0);
if (this.fileInput.nativeElement.value != '')
{
this.upload();
}
}
upload()
{
const formData: FormData = new FormData();
formData.append('file', this.fileToUpload, this.fileToUpload.name);
this.params.map(param => {
formData.append(param.key, param.value);
});
let headers = {};
this.httpClient
.post(this.apiUrl, formData, { headers: headers })
// .map(() => { return true; })
.subscribe(response => {
this.onUploadSuccess(this.fileToUpload, response);
this.fileInput.nativeElement.value = '';
}, error => {
this.onUploadError(error);
});
}
}
src/components/file-uploader/file-uploader.html
<div>
<input type="file" #file (change)="onFileInputChange($event.target.files)">
<button *ngIf="buttonType == 'button'" ion-button (click)="triggerFileInputClick()">{{buttonText}}</button>
<ion-icon *ngIf="buttonType == 'icon'" name="cloud-upload" (click)="triggerFileInputClick()"></ion-icon>
</div>
src/components/file-uploader/file-uploader.scss
file-uploader {
[type=file] {
display: none;
}
}
src/pages/home/home.html
<file-uploader [apiUrl]="apiUrl" [params]="[{'key':'language_code', 'value': languageCode}]"></file-uploader>
All you need to do now is load the component in the NgModule and use it.
Last thing I should mention is if you have problems with undefined attributes e.g. apiUrl, you should initialize them in the ngOnInit() method.
Hope that helps
UPDATE Don't forget to import file uploader into the component that is using uploader or else you'll get Can't bind to 'apiUrl' since it isn't a known property of 'file-uploader' error. What I did is I created new module components.module.ts file in the components folder. Then I imported file uploader component into it. To use it I imported components module into the component that is using the file uploader component.
src/components/components.module.ts
import { IonicModule } from 'ionic-angular';
import { NgModule } from '@angular/core';
import { FileUploaderComponent } from './file-uploader/file-uploader';
@NgModule({
declarations: [
FileUploaderComponent
],
imports: [
IonicModule,
],
exports: [
FileUploaderComponent
]
})
export class ComponentsModule {}
src/pages/home/home.module.ts
import { ComponentsModule } from '../../components/components.module';
Upvotes: 2