ionic-native/chooser never resolve/reject promise

Created on 10 Oct 2018  Â·  10Comments  Â·  Source: ionic-team/ionic-native

I'm submitting a ... (check one with "x")
[X ] bug report
[ ] feature request
[ ] support request => Please do not submit support requests here, use one of these channels: https://forum.ionicframework.com/ or https://ionicworldwide.herokuapp.com/

Current behavior:
The chosen file is correctly readed by the cordova plugin but ionic-native ( https://ionicframework.com/docs/native/chooser/ ) can't get the resolved/rejectect promise.

Expected behavior:
The promise must resolve or reject.

Steps to reproduce:
Install the plugin. Import module in AppModule. Use the example code after platform is ready and page initialized.

Related code:

import { Chooser } from '@ionic-native/chooser';
constructor(private chooser: Chooser) { }
...
this.chooser.getFile() 
  .then(file => console.log(file ? file.name : 'canceled'))
  .catch((error: any) => console.error(error));

Other information:
I've forked the cordova-plugin-chooser project and implemented www/chooser.js with callbacks instead of promise and it works. ( https://github.com/wideLandscape/cordova-plugin-chooser ).
To use the forked plugin you need to replace typescript definition in \node_modules@ionic-native\chooser\index.d.ts with the index.d.ts file in the root folder of the forked repo.

Tested on real device Huawei Mate 10 lite, EMUI: 5.1, Android: 7.0
If someone could test it on iOS that would be great.

Ionic info: (run ionic info from a terminal/cmd prompt and paste output below):

Ionic:
ionic (Ionic CLI) : 4.2.0
Ionic Framework : ionic-angular 3.9.2
@ionic/app-scripts : 3.2.0

Cordova:
cordova (Cordova CLI) : 8.0.0
Cordova Platforms : android 7.0.0

System:
Android SDK Tools : 26.1.1
NodeJS : v8.11.4
npm : 6.4.1
OS : Windows 10

Most helpful comment

Hi @wideLandscape while working on this issue you can make direct use of the cordova plugin. Example

    (async () => {
        const file = await (<any>window).chooser.getFile("application/pdf");
        if (file.name) console.log(`File ${file.name} selected`);
    })();

Hi. In my case, it is the only working solution I've found.
Also tried wideLandscape's one without luck.
Note that if you substitute _(window).chooser_ by _this.chooser_ then it doesn't resolve.
Thank you

All 10 comments

I needed a chooser plugin so I decided to give this one a try (since it supports both android and iOS), but ran into the same issue. The root cause of the problem is that the getFile method returns a promise and the plugin is decorated wrong and assumes (regular) callback (ie. success/error) functions are used.

@wideLandscape Hi, i hv tried replacing index.d.ts with the one in forked repo.
i got these error, Expected 2-3 arguments, but got 1.
is the call method different than this?
this.chooser.getFile('application/pdf')
.then((file:any) => console.log(file ? file.name : 'canceled'))
.catch((error: any) => console.error(error));

Hi @wideLandscape while working on this issue you can make direct use of the cordova plugin. Example

    (async () => {
        const file = await (<any>window).chooser.getFile("application/pdf");
        if (file.name) console.log(`File ${file.name} selected`);
    })();

@wideLandscape Hi, i hv tried replacing index.d.ts with the one in forked repo.
i got these error, Expected 2-3 arguments, but got 1.
is the call method different than this?
this.chooser.getFile('application/pdf')
.then((file:any) => console.log(file ? file.name : 'canceled'))
.catch((error: any) => console.error(error));

Hi cikcoh,
you need to install my version of the plugin first:
npm install https://github.com/wideLandscape/cordova-plugin-chooser
and then copy index.d.ts you to \node_modules@ionic-native\chooser\index.d.ts

Because callback is implemented instead of promise you need to use the chooser plugin in this way:

this.chooser.getFile(
      file => {
       console.log(file.data.buffer);
        }
      },
      error => console.error(error)
    );

first argument is a function with the selected file as parameter;
second is a function for managing errors;
third parameter is optional and indicates accepted formats (eg: '.jpg,.jpeg,.png,.bmp,image/jpeg,image/png,image/bmp')
Hope it helps

Hi @wideLandscape while working on this issue you can make direct use of the cordova plugin. Example

    (async () => {
        const file = await (<any>window).chooser.getFile("application/pdf");
        if (file.name) console.log(`File ${file.name} selected`);
    })();

Hi. In my case, it is the only working solution I've found.
Also tried wideLandscape's one without luck.
Note that if you substitute _(window).chooser_ by _this.chooser_ then it doesn't resolve.
Thank you

Same issue here …
To make it works :

  1. I removed native chooser plugin but I kept the cordova-plugin-chooser
  2. I added "declare var cordova: any;" at the end of the file "/src/declaration.d.ts"
  3. In the ts file of the page where I needed the plugin :

    1. I created a private attribute "chooser"

    2. In the constructor, I initialized the chooser :
      this.chooser = cordova.require("cordova-plugin-chooser.Chooser");

    3. Use the chooser like the example and it worked !

Hi there, just use @wideLandscape 's repo.

First, delete the whole folder cordova-plugin-chooser under pulgin folder.
then
install his repo as corodva-plugin-chooser

npm install https://github.com/wideLandscape/cordova-plugin-chooser

This will change the version of cordova-plugin-chooser in package.json to

"cordova-plugin-chooser": "git+https://github.com/wideLandscape/cordova-plugin-chooser.git",

in config.xml
`

`

  1. If needed just remove and add the platform again.

  2. If you run ionic4, you can build your own chooser wrapper with @wideLandscape 's code. It very simple. After that you got the new chooser wrapper to use.

This is not the perfect solution.
Just as @chancezeus mentioned, there is a problem between ionic teams' wrapper and the cordova-plugin.

My code below works.
`
const onSuccess = (data)=>{
console.log(data);
};

const onError = (error)=>{
  console.error(error);
}

this.chooser.getFile(onSuccess, onError,"image/jpeg");

`

Hey everyone. I was hoping someone from Ionic would've chimed in with a fix by now, since the issue is definitely specific to Ionic given that @ffcc's solution works.

Anyway, I just got a chance to look into this, and it _seems_ like what's happening is that Ionic tries to wrap every plugin method in a promise without accounting for the possibility that the plugin already returns a promise. The apparent fix was just to add (undocumented) success and failure callbacks to my plugin, which should cause Ionic's promise to now work as intended.

I don't have an Ionic app readily available for testing, so I'm not 100% sure that this fixed the problem, but just let me know if any of you guys still have issues with the latest cordova-plugin-chooser.

Hi @wideLandscape while working on this issue you can make direct use of the cordova plugin. Example

    (async () => {
        const file = await (<any>window).chooser.getFile("application/pdf");
        if (file.name) console.log(`File ${file.name} selected`);
    })();

i applied Audio/mp3 instead of application/pdf on applying this i get his error message

vendor-es2015.js:46777 ERROR Error: Uncaught (in promise): TypeError: fullPath.indexOf is not a function

TypeError: fullPath.indexOf is not a function
at AddAudioPage.copyFileToLocalDir (pages-mediachat-add-audio-add-audio-module-es2015.js:259)
at AddAudioPage. (pages-mediachat-add-audio-add-audio-module-es2015.js:246)
at Generator.next ()
at fulfilled (vendor-es2015.js:184496)
at ZoneDelegate.invoke (polyfills-es2015.js:3365)
at Object.onInvoke (vendor-es2015.js:71868)
at ZoneDelegate.invoke (polyfills-es2015.js:3364)
at Zone.run (polyfills-es2015.js:3130)
at polyfills-es2015.js:3861
at ZoneDelegate.invokeTask (polyfills-es2015.js:3397)
at resolvePromise (polyfills-es2015.js:3803)
at polyfills-es2015.js:3713
at fulfilled (vendor-es2015.js:184496)
at ZoneDelegate.invoke (polyfills-es2015.js:3365)
at Object.onInvoke (vendor-es2015.js:71868)
at ZoneDelegate.invoke (polyfills-es2015.js:3364)
at Zone.run (polyfills-es2015.js:3130)
at polyfills-es2015.js:3861
at ZoneDelegate.invokeTask (polyfills-es2015.js:3397)
at Object.onInvokeTask (vendor-es2015.js:71849)

As noted in the cordova-plugin-chooser readme, it returns a promise that resolves to undefined when the user doesn't select a file, so if (file.name) is actually incorrect (you would want to use just if (file)).

As far as your error @08Thug, is it reproducible if you pass in "audio/mp3"? The issue here may be that it's treating mime types as case-sensitive, and for whatever reason behaving as though the file selection was cancelled when it sees an "invalid" mime type, in which case I can fix it by throwing a .toLowerCase() into the plugin.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

vaibsVB picture vaibsVB  Â·  4Comments

hobbydevs picture hobbydevs  Â·  3Comments

GunaSekhar1 picture GunaSekhar1  Â·  4Comments

danbucholtz picture danbucholtz  Â·  3Comments

icchio picture icchio  Â·  3Comments