How-TosUncategorized

[IONIC] Image Upload in Ionic 4

1*lTsIggbdUP1LdngkpqwL w

While working in some project the other day, I faced challenge in creating a feature to upload images in the App, built using Ionic 4. I struggled a lot, followed a lot of posts and links available online, but of no good.
I felt the official documentation is somewhat not complete or i might be doing something wrong.

But whatever it is, finally I got success in creating the feature. So thought of sharing it.

Overview

The feature is to enable the App user to either click or select from gallery and upload the image. I am using Ionic 4, NodeJS for APIs and S3 for file storage. I won’t go into the backend part. I’ll just describe how to make the feature in Ionic App.

Plugins Required

For this we mainly require 4 Ionic native plugins:

  1. Camera
  2. File
  3. WebView
  4. FilePath

Install these plugins and include them in the app.module.ts file in the project and add them in the Providers.

In your page, where you want the feature, import these plugins.

import { WebView } from '@ionic-native/ionic-webview/ngx';
import { File, FileEntry } from '@ionic-native/File/ngx';
import { Camera,CameraOptions,PictureSourceType } from '@ionic-native/camera/ngx';
import { FilePath } from '@ionic-native/file-path/ngx';

So now lets add functionalities step-by-step.

First we need an ActionSheet to show options to Capture or to Select from Gallery.

async selectImage() {
const actionSheet = await this.actionSheetController.create({
header: 'Select Image source',
buttons: [{
text: 'Load from Library',
handler: () => {
this.takePicture(this.camera.PictureSourceType.PHOTOLIBRARY);
}
},
{
text: 'Use Camera',
handler: () => {
this.takePicture(this.camera.PictureSourceType.CAMERA);
}
},
{
text: 'Cancel',
role: 'cancel'
}]
});
await actionSheet.present();
}

Now lets handle each of these option. We need to define the takePicture function. This is a crucial part.

takePicture(sourceType: PictureSourceType) {
const options: CameraOptions = {
quality: 100,
sourceType: sourceType,
saveToPhotoAlbum: false,
correctOrientation: true
};
this.camera.getPicture(options).then(imagePath => {
if (this.plt.is('android') && sourceType ===
this.camera.PictureSourceType.PHOTOLIBRARY) {
this.filePath.resolveNativePath(imagePath).then(filePath => {
const correctPath = filePath.substr(0, filePath.lastIndexOf('/') + 1);
const currentName = imagePath.substring(
imagePath.lastIndexOf('/') + 1,
imagePath.lastIndexOf('?'));
this.copyFileToLocalDir(
correctPath,
currentName,
this.createFileName()
);
});
} else {
const currentName = imagePath.substr(imagePath.lastIndexOf('/') + 1);
const correctPath = imagePath.substr(0, imagePath.lastIndexOf('/') + 1);
this.copyFileToLocalDir(
correctPath,
currentName,
this.createFileName()
);
}
});
}

Basically, the important thing is the path to the image. Getting the correct path of the image in both the options are different. Next we will have to get the image using the path and store it in the local storage of the App. For that we might need to assign a name to that image file. So lets first define the createFileName function and then we will see how to store the image in storage using the function copyFileToLocalDir.

createFileName() {
const d = new Date(),
n = d.getTime(),
newFileName = n + '.jpg';
return newFileName;
}
copyFileToLocalDir(namePath, currentName, newFileName) {
this.file.copyFile(namePath, currentName, this.file.dataDirectory, newFileName).then(
success => {
this.updateStoredImages(newFileName);
this.presentToast('Success while storing file.');
},
error => {
this.presentToast('Error while storing file.');
});
}

Now that we are ready our function is holding the image, we will store its info in our local storage. Lets define the function updateStoredImages to update our storage with a key holding our image informations.

updateStoredImages(name) {
this.storage.get(STORAGE_KEY).then(images => {
let arr = [];
if (images && images !== '' && images.length > 0) {
arr = JSON.parse(images);
} else {
arr = [];
}
if (!arr) {
const newImages = [name];
this.storage.set('my_images', JSON.stringify(newImages));
} else {
arr.push(name);
this.storage.set('my_images', JSON.stringify(arr));
}
const filePath = this.file.dataDirectory + name;
const resPath = this.pathForImage(filePath);
const newEntry = {
name: name,
path: resPath,
filePath: filePath
};
this.images = [newEntry, ...this.images];
});
}

Now our images are stored in storage. You can now view these in the UI. And add 2 buttons, one for Upload and one to Delete.

Upload Function

On click of Upload Button, call a function to upload the image to the server. Pass the object and the index on click function.

1*t7VQT0 7y0fDSdV07nYJ A
Code Snippet in the HTML Page
startUpload(imgEntry, position) {
this.file
.resolveLocalFilesystemUrl(imgEntry.filePath)
.then(entry => {
(<FileEntry>entry).file(file => this.readFile(file, imgEntry, position));
})
.catch(err => {
this.presentToast('Error while reading file.');
});
}

This function will get the local file system URL and pass it to read the file.

readFile(file: any, imgEntry, position) {
const reader = new FileReader();
reader.onload = () => {
const formData = new FormData();
const imgBlob = new Blob([reader.result], {
type: file.type
});
formData.append('file', imgBlob, file.name);
this.uploadImageData(formData, imgEntry, position);
};
reader.readAsArrayBuffer(file);
}

readFile function will read the file and create formData, basically prepare to post to the API.

async uploadImageData(formData: FormData, imgEntry, position) {
const loading = await this.loadingController.create({
message: 'Uploading image...'
});
await loading.present();
this.http.post(`<<YOUR API>>`, formData).pipe(finalize(() => {
loading.dismiss();
})
)
.subscribe(res => {
if (res['success']) {
this.presentToast('File upload complete.');
} else {
this.presentToast('File upload failed.');
}
});
}
}

Finally the image is uploaded. Now you can handle and store your file as per your convenience.

To delete the file from Storage (NOTE: Not from Server), a simple delete function will do the job.

deleteImage(imgEntry, position) {
this.images.splice(position, 1);
this.storage.get('my_images').then(images => {
const arr = JSON.parse(images);
const filtered = arr.filter(name => name !== imgEntry.name);
this.storage.set('my_images', JSON.stringify(filtered));
const correctPath = imgEntry.filePath.substr(0,
imgEntry.filePath.lastIndexOf('/') + 1);
this.file.removeFile(correctPath, imgEntry.name).then(res => {
this.presentToast('File removed.');
});
});
}

That’s it. Done.

Reference/Credit:

https://devdactic.com/ionic-4-image-upload-storage/

NOTE: Coding doesn’t have a perfect or exact technique. This is what I did. You can always try out or enhance your code. Please let me know if you find out any other awesome way to upload images and do share with me.

In case you need any help related to Image Upload in Ionic or you have some suggestions, feel free to drop an email at [email protected]

Rajesh Mishra

I'm a developer who loves sharing insights, technical how-tos, and lessons learned from the world of code. While much of what I write may not be groundbreaking, I believe in documenting for future me—and for anyone else who might find it useful. Beyond tech, I also dive into life's experiences and moments, reflecting on personal growth and sharing stories that resonate. Whether you're here for practical tips or a fresh perspective on life, I hope you find something meaningful.

Leave a Reply

Your email address will not be published. Required fields are marked *