Cannot read property 'URI' of undefined

I got this error whenever I try to use native screenshot method in Ionic2.

My code:

this.screenshot.URI(80).then((result) => {
  console.log(result);
}, (err) => {
  console.log(err);
});

Have you added the screenshot plugin in the providers array in app.module.ts and have you DI the provider in your constructor?

import { Screenshot } from '@ionic-native/screenshot';

...

@NgModule({
  ...

  providers: [
    ...
    Camera
    ...
  ]
  ...
})
export class AppModule { }

And in your page or provider

import { Screenshot } from '@ionic-native/screenshot';
...
constructor(private screenshot: Screenshot) { }

Yes, I have everything as you mentioned.
Also, this is my package.json:

"dependencies": {
    "@angular/common": "4.0.0",
    "@angular/compiler": "4.0.0",
    "@angular/compiler-cli": "4.0.0",
    "@angular/core": "4.0.0",
    "@angular/forms": "4.0.0",
    "@angular/http": "4.0.0",
    "@angular/platform-browser": "4.0.0",
    "@angular/platform-browser-dynamic": "4.0.0",
    "@ionic-native/camera": "^3.6.0",
    "@ionic-native/core": "3.6.1",
    "@ionic-native/file": "^3.6.0",
    "@ionic-native/file-path": "^3.6.0",
    "@ionic-native/screenshot": "^3.6.1",
    "@ionic-native/splash-screen": "3.4.2",
    "@ionic-native/status-bar": "3.4.2",
    "@ionic-native/transfer": "^3.6.0",
    "@ionic/storage": "2.0.1",
    "crypto-js": "3.1.9-1",
    "fast-sha256": "1.0.0",
    "ionic-angular": "3.0.1",
    "ionic-native": "^3.5.0",
    "ionicons": "3.0.0",
    "rxjs": "5.1.1",
    "sha256": "0.2.0",
    "sw-toolbox": "3.4.0",
    "ts-md5": "1.2.0",
    "zone.js": "^0.8.4"
  },
  "devDependencies": {
    "@ionic/app-scripts": "1.3.0",
    "typescript": "~2.2.1"
  },
  "cordovaPlugins": [
    "cordova-plugin-whitelist",
    "cordova-plugin-console",
    "cordova-plugin-statusbar",
    "cordova-plugin-device",
    "ionic-plugin-keyboard",
    "cordova-plugin-splashscreen"
  ],

You should remove the ionic-native entry, because recently you use the @ionic-native/… packages instead of ionic-native package
Also you should use same versions for all your @ionic-native/… packages
but I don’t know, if that solves your problem

Can you show, where you use the code snippet?

Have you added the plugin?

$ ionic plugin add --save https://github.com/gitawego/cordova-screenshot.git

I would use these package.json dependencies:

"dependencies": {
    "@angular/common": "4.0.2",
    "@angular/compiler": "4.0.2",
    "@angular/compiler-cli": "4.0.2",
    "@angular/core": "4.0.2",
    "@angular/forms": "4.0.2",
    "@angular/http": "4.0.2",
    "@angular/platform-browser": "4.0.2",
    "@angular/platform-browser-dynamic": "4.0.2",
    "@ionic-native/camera": "3.6.1",
    "@ionic-native/core": "3.6.1",
    "@ionic-native/file": "3.6.1",
    "@ionic-native/file-path": "3.6.1",
    "@ionic-native/screenshot": "3.6.1",
    "@ionic-native/splash-screen": "3.6.1",
    "@ionic-native/status-bar": "3.6.1",
    "@ionic-native/transfer": "3.6.1",
    "@ionic/storage": "2.0.1",
    "crypto-js": "3.1.9-1",
    "fast-sha256": "1.0.0",
    "ionic-angular": "3.1.1",
    "ionicons": "3.0.0",
    "rxjs": "5.1.1",
    "sha256": "0.2.0",
    "sw-toolbox": "3.4.0",
    "ts-md5": "1.2.0",
    "zone.js": "0.8.10"
  },
  "devDependencies": {
    "@ionic/app-scripts": "1.3.6",
    "typescript": "2.2.2"
  },
  "cordovaPlugins": [
    "cordova-plugin-whitelist",
    "cordova-plugin-console",
    "cordova-plugin-statusbar",
    "cordova-plugin-device",
    "ionic-plugin-keyboard",
    "cordova-plugin-splashscreen"
  ],

Then save the package.json, delete node_modules folder and
npm install

Which ionic-native entry do you mean?

I use it in provider class in simple function called in another function:

startPing(details) {
//code

this.makeScreenshot();

//more code
}

makeScreenshot() {
    this.screenshot.URI(80).then((result) => {
      console.log(result);
    }, (err) => {
      console.log(err);
    });
}


Yes I have added that plugin. Running this command again gives me messages that all of the files already exist so I guess everything is there.

You could try to restore the plugins and platforms from package.json with
ionic state restore

but make a backup before that

Can you show the complete content of your file?

Show us your app.module.ts and the file where you actually try to use it (complete with imports and constructor) please.

ok, app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { IonicStorageModule } from '@ionic/storage'
import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { LoginPage } from '../pages/login-page/login-page';
import { SignupPage } from '../pages/signup-page/signup-page';
import { Auth } from '../providers/auth';
import { Data } from '../providers/data';
import { StatusBar } from '@ionic-native/status-bar';
import { SplashScreen } from '@ionic-native/splash-screen';
import { HttpModule } from '@angular/http';
import { CalendarPage } from '../pages/calendar-page/calendar-page';
import { OptionsPage } from '../pages/options-page/options-page';
import { ScreensPage } from '../pages/screens-page/screens-page';
import { TasksPage } from '../pages/tasks-page/tasks-page';
import { MoreContentPage } from '../pages/tasks-page/tasks-page';
import { WorkTimePage } from '../pages/work-time-page/work-time-page';
import { PasswordRestoringPage } from '../pages/password-restoring-page/password-restoring-page';
import { ChangePasswordPage } from '../pages/change-password-page/change-password-page';
import { TaskCreatePage } from '../pages/task-create-page/task-create-page';
import { File } from '@ionic-native/file';
import { FilePath } from '@ionic-native/file-path';
import { Camera } from '@ionic-native/camera';
import { Transfer } from '@ionic-native/transfer';
import { Screenshot } from '@ionic-native/screenshot';



@NgModule({
  declarations: [
    MyApp,
    HomePage,
    LoginPage,
    SignupPage,
    CalendarPage,
    OptionsPage,
    ScreensPage,
    TasksPage,
    WorkTimePage,
    PasswordRestoringPage,
    ChangePasswordPage,
    MoreContentPage,
    TaskCreatePage
  ],
  imports: [
    HttpModule,
    BrowserModule,
    IonicModule.forRoot(MyApp),
    IonicStorageModule.forRoot()
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage,
    LoginPage,
    SignupPage,
    CalendarPage,
    OptionsPage,
    ScreensPage,
    TasksPage,
    WorkTimePage,
    PasswordRestoringPage,
    ChangePasswordPage,
    MoreContentPage,
    TaskCreatePage
  ],
  providers: [HttpModule, IonicErrorHandler, Auth, Data, SplashScreen, StatusBar, Camera, Transfer, FilePath, File, Screenshot]
})
export class AppModule {}

and data.ts provider

import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import { Storage } from '@ionic/storage';
import { Screenshot } from '@ionic-native/screenshot';
import { Platform } from 'ionic-angular';
import Rx from 'rxjs/Rx';
import 'rxjs/add/operator/map';

@Injectable()
export class Data {


  public Projects: any;
  public Project: any;
  public Tasks: any;
  public Task: any;
  public Companies: any;
  public Company: any;

  public Source: any;
  public Subscription: any;
  public Image: any;

  public IsWorking: boolean;
  public TotalHoursAllProjects: any;
  public TotalHoursAllProjectsToday: any;
  public TotalHoursCurrentProject: any;
  public TotalHoursCurrentProjectToday: any;


  constructor(public http: Http,
    public storage: Storage,
    public platform: Platform,
    private screenshot: Screenshot) {

  }

  startPing(details) {

    let startingTime = new Date(Math.ceil(new Date().getTime() / 600000) * 600000);

    return new Promise((resolve, reject) => {

      let headers = new Headers();
      headers.append('Content-Type', 'application/json');

      this.Source = Rx.Observable.timer(startingTime, 600000).timeInterval().pluck('interval');

      this.makeScreenshot();

      this.Subscription = this.Source
        .subscribe(data => {
          let pingDetails = {
            Token: details.Token,
            ProjectId: details.ProjectId,
            Timestamp: new Date().toISOString(),
            IsOldPing: false,
            Image: this.Image
          };

          console.log(pingDetails);

          this.http.post('http://localhost:63203/api/Ping', JSON.stringify(pingDetails), { headers: headers })
            .map(res => res.json())
            .subscribe(data => {
              this.showPingToast();
              this.TotalHoursAllProjects = data.TotalHoursAllProjects;
              this.TotalHoursAllProjectsToday = data.TotalHoursAllProjectsToday;
              this.TotalHoursCurrentProject = data.TotalHoursCurrentProject;
              this.TotalHoursCurrentProjectToday = data.TotalHoursCurrentProjectToday;
              resolve(data);
            }, (err) => {
              reject(err);
            });
        });
    });
  }


makeScreenshot() {
    this.platform.ready().then(() => {
      this.screenshot.URI(80).then((result) => {
        console.log(result);
      }, (err) => {
        console.log(err);
      });
    });
  }

Does it work if you get rid of the makeScreeshot() and inline the code?

no, I even tested this in other places and everywhere I got this same error

Ok, few steps back: Can you please copy the exact error message you are getting?
Can you also console.log(this.screenshot) there and copy the output?

Console.log(this.screenshot):

Screenshot {}
__proto__
:
IonicNativePlugin
URI
:
function (quality)
constructor
:
function Screenshot()
save
:
function (format, quality, filename)
__proto__
:
Object

And full error message:

TypeError: Cannot read property 'URI' of undefined
    at index.js:71
    at new t (polyfills.js:3)
    at Screenshot.URI (index.js:70)
    at Promise (data.ts:53)
    at new t (polyfills.js:3)
    at Data.startPing (data.ts:44)
    at HomePage.startPing (home.ts:62)
    at Object.eval [as handleEvent] (HomePage.html:45)
    at handleEvent (core.es5.js:11805)
    at callWithDebugContext (core.es5.js:13013)
    at Object.debugHandleEvent [as handleEvent] (core.es5.js:12601)
    at dispatchEvent (core.es5.js:8780)
    at core.es5.js:9370
    at HTMLButtonElement.<anonymous> (platform-browser.es5.js:2683)
    at t.invokeTask (polyfills.js:3)

Can you call console.log(this.screenshot) directly before this.screenshot.URI(80)... or have you called it there already? Does it log the same or does it log undefined?

You could try this.screenshot['URI'](80)...

Ok, this doesn’t really make any sense. The log shows us there is a .URI() and then calling it gives you an error message? I don’t know what to do know, besides ask you to check the lines from the error message and see if this is maybe something totally unrelated.

Yes, it was called before.
I know it doesn’t make sense and at this point I have no clue what to do next.

I have same probrem.

1 Like

Ugh, same problem here. The other method of save works, this doesn’t.

2 Likes

Ensure that the platform is ready before attempting to interact with any native plugins.

8 posts were split to a new topic: Console.log(this.screenshot) gives me a normal result, but this.screenshot.URI() does not work

Facing the same issue. Did anyone found the solution yet?