Ionic View and Ionic DevApp can't use file and file-path cordova plugins

I would like to upload an image to my back-end using FormData, but as Ionic DEVAPP and Ionic VIEW does not support file, file-transfer and file-upload plugins, I need to do it using only Angular Http or HttpClient.

When using DestinationType.FILE_URI, I can get the internal url from the file and display it on a img object, but I can’t create a typescript File object from this url without the native file, file-path and file-transfer plugins.

getImage() {
const options: CameraOptions = {
  quality: 100,
  destinationType: this.camera.DestinationType.FILE_URI,
  sourceType: this.camera.PictureSourceType.PHOTOLIBRARY
}

this.camera.getPicture(options).then((imageData) => {
  this.imageURI =  this.sanitizer.bypassSecurityTrustUrl(imageData)
}, (err) => {
  console.log(err)
  this.presentToast(err)
})

using this template

<ion-content padding>
  <ion-item>
    <p>{{imageFileName}}</p>
    <button ion-button color="secondary" (click)="getImage()">Get Image</button>
  </ion-item>
  <ion-item>
    <h4>Image Preview</h4>
    <img style="display:block" [src]="imageURI" *ngIf="imageURI" alt="Ionic File" width="300" />
  </ion-item>
  <ion-item>
    <button ion-button (click)="uploadFile()">Upload</button>
  </ion-item>
</ion-content>

When using DestinationType.DATA_URL I can display the image but can not create the typescript File object needed with the original file name to append the image to the FormData used on my upload service at my Ionic App.

It seems I can not find a way to create this typescript File object with the original filename from FILE_URI and the base64 encoded data from DATA_URL using the camera.getPicture from the cordova camera native plugin. All posts about this concern solve the issue using file, file-path and file-transfer plugins unsupported in Ionic DevApp and Ionic View.

Service to upload the file to my back-end just uses this approach:

postImage(image: File): Observable<any> {
  constformData = new FormData().append('file', image, image.name)
  return this.httpClient.post<any>(this.myUrl,formData)
}

Both getImage from component myPage.ts and postImage from uploadservice.ts work fine, but I can’t find a way to create the File object from camera.getPicture imageData.

Can’t understand how to test and modify a project for both iOS and Android without DevApp or get testers on both without Ionic View. Can’t understand why nobody is using image post to a back-end on Ionic View or DevApp.

EDIT

I have found some options to go from imageData (DATA_URL destination type) base64 encoded image to a File object. Some of them using a blob in between, but the outcome is the same:

    this.camera.getPicture(options).then((imageData) => {
      this.imageURI =  this.sanitizer.bypassSecurityTrustUrl("data:image/jpeg;base64," + imageData)
      const imageFile = new File([imageData], 'myImage.jpg', { type: 'image/jpeg' })
      console.log(fitxer)
    }
  }

but the resulting File object seem to have some properties misplaced. Inspecting imageFile.name shows an array where the original encoded data is shown, size and start properties are 0 and but seems correct.

File {name: Array(1), localURL: "myImage.jpg", type: Object, lastModified: null, lastModifiedDate: null, …}
main.js:89
end:0
lastModified:null
lastModifiedDate:null
localURL:"myImage.jpg"
name:Array(1) ["/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEBAQEBAQ…"]
size:0
start:0
type:Object {type: "image/jpeg"}
__proto__:Object {slice: , constructor: }

Same file creation process

file = new File ([encoded string], 'placomerc.jpg', {type: 'image/jpeg'})

on an Angular 4 clean project outputs all object’s properties correctly:

File(53607) {name: "placomerc.jpg", lastModified: 1512739184702, lastModifiedDate: Fri Dec 08 2017 14:19:44 GMT+0100 (Hora estándar r…, webkitRelativePath: "", size: 53607, …}
lastModified:1512739184702
lastModifiedDate:Fri Dec 08 2017 14:19:44 GMT+0100 (Hora estándar romance) {}
name:"placomerc.jpg"
size:53607
type:"image/jpeg"
webkitRelativePath:""
__proto__:File {name: <accessor>, lastModified: <accessor>, lastModifiedDate: <accessor>, …}

On a fresh clean new Ionic project, File object creation, even of simple ‘text/plain’ type, outputs a wrong constructed object:

const textfile = new File (['text'], 'text.txt')
console.log(textfile)

File {name: Array(1), localURL: "text.txt", type: null, lastModified: null, lastModifiedDate: null, …}
main.js:91
end:0
lastModified:null
lastModifiedDate:null
localURL:"text.txt"
name:Array(1) ["text"]
size:0
start:0
type:null
__proto__:Object {slice: , constructor: }

So as for now, it seems it’s my misconception about the creation of Object File on typescript/angular Ionic implementation, or a bug in this functionality.
I will keep posting my progress -even without any suggestion from forum staff members- just for possible further searches of Ionic users stuck on this issue.

EDIT 2

I went a step forward to refine the issue. This simple line of code:

const textfile = new File (['text'], 'text.txt', {type: 'text/plain'})

Will generate a diferent outcome on Angular development inspection and on Angular/Ionic inspection.

While on Angular you’ll get what you expect, on Angular/Ionic3 the properties seem misplaced:

File {name: Array(1), localURL: "text.txt", type: Object, lastModified: null, lastModifiedDate: null, …}
end:0
lastModified:null
lastModifiedDate:null
localURL:"text.txt"
name:Array(1) ["text"]
size:0
start:0
type:Object {type: "text/plain"}
__proto__:Object {slice: , constructor: }

as name property is an Array Array(1) [“text”] containing the body of the file, and end, size and start properties are 0.
On Angular 4 the same code outputs a File object with all properties on place and ready to server upload:

File(13) {name: "text.txt", lastModified: 1520684955392, lastModifiedDate: Sat Mar 10 2018 13:29:15 GMT+0100 (Hora estándar r…, webkitRelativePath: "", size: 13, …}
classes.ts:636
lastModified:1520684955392
lastModifiedDate:Sat Mar 10 2018 13:29:15 GMT+0100 (Hora estándar romance) {}
name:"text.txt"
size:13
type:"text/plain"
webkitRelativePath:""
__proto__:File {name: <accessor>, lastModified: <accessor>, lastModifiedDate: <accessor>, …}

Just in case, I have already tried on “Run Android on device” and “Run Browser” (chrome) so I think is not about the technology of the client. Even more as on Angular 4 is working as expected.

Not a direct reply to your question or even a solution:

Why do you want to use Ionic View or Ionic DevApp?

Have you thought about maybe just building your app locally? What you are trying to do clearly is not the best usecase for both apps, but will be no problem with just building the app yourself (which is the end goal anyway for any app built with Ionic, right?).

The principled solution here is to build a file handler in Capacitor. Does anyone know if that’s already in progress? OP, in the meantime, you can write mocks of the plugins so you can test, or you could use the existing mocks from here.

In general though, the long term move is away from Cordova, and I try not to use Cordova if I can avoid it, despite the amount of great work that went into it over the years.

There are a lot of non-Cordova tools for this. angular2-image-upload, ng-img-tools, lots more. Search on npm for “angular image” or “ng image.” I can hear you are frustrated, but this is a non-problem.

I told you a month ago on a different thread that cordova file-transfer was sunsetted and you should use something else. Instead, a month later, you post this thread complaining that Ionic View does not support cordova file-transfer. Well, Ionic View shouldn’t – it’s a sunsetted plugin. It isn’t my fault you didn’t take my advice.

Got my first real suggestion about the issue. It seems a matter of ionic-cordova-plugins interfering with typescript/angular File object constructor.

Removing plugins from project allows Angular/Ionic to correctly create the FIle object.

1 Like

I had that issue, too.
workaround:
You could make a var in a script tag in the index html before loading cordova and let that var store the unchanged file object. Then declare that var in your typescript definitions and use it.

//index.html
<script>
var VanillaFile = File;
</script>
// the cordova js import has to be after that

//declarations.d.ts
declare class VanillaFile extends File {} 
1 Like

Thanks for your code! I found another way to do it.

It may sound obvious but removing File, File-Path and File-Transfer plugins and @ionic-native references to those native features, the Angular/Typescript based File Object started creating ok.

Now the only plugin from cordova added to those generated by ionic start cli command is cordova-plugin-camera.

This means that, once the file object created, send picture from camera/gallery to server feature is working on Angular background just using FormData and HttpClient.

And more amazing: it works on DevApp and Ionic View!!

If anybody is interested on how to upload pictures to a back-end without third party libraries (ng-upload, ng-image,…) and no DevApp/View unsupported plugins, just ask for it and I will post a sample code.

Thanks again @user5555

Your welcome :wink:
can you mark the topic as solved?

You are right.
Done!

Could you elaborate a bit more your solution?
I have been testing it but Ionic seems unsatisfied with that

var VanillaFile = File;

line of code at index.html.

When I’m home again, I could copy paste my code parts

Oh wait. I’ve found the trick.
Please don’t waste your time in this. I’m gonna write a complete post with how-to test server image upload using DevApp and View.
Thanks for your will.
PS.: You’ll gonna be credited :wink::grinning:

1 Like

As far as importing the Ionic File plugin in a way that avoids name collision, I find this much better:

import { File as IonicFileService } from '@ionic-native/file';

This let’s you continue to use the built in native File type with it’s expected name, rather than trying to rewrite the default File object with a new name and letting Ionic’s poor naming mess things up.

1 Like

Does that work? Is it really that easy? I’ll have to test this…
EDIT: no I don’t think that’s that easy, because the cordova File plugin changes the global thing - Its sth. in Cordova JS nothing with Ionic.

Hmm, it worked fine for me, but I see what you mean that file is defined in the actual plugins js file. So…I’m not sure honestly, unless the typescript typings override any other definitions unless they are explicitly imported. Maybe Typescript is fine with it but when it compiles it actually uses the other File type, which unlike the native file type does not extend Blob.

But, my code does work and Typescript connects me to the correct type, so, not sure honestly:
image

Edit: As part of the build process the File function defined by cordova is wrapped in a module export, so theoretically it will not be a global variable and won’t be used unless imported

image

It overrides with cordova.js before the compiled typescript gets to see the real one. As far as I’m concerned.

Can you post the sample code? I am in similar situation.

Can you please post your solution? Thanks.

Sure I will.
Just excuse-me until week-end to post code and explanation.
I’m sorry if you are in a hurry, but I’m under a deadline tomorrow!
Happy coding!