26

After reading everything I could find, and failing, I must ask here:

I am trying to use ionic2's Storage, just like the doc tells me to,

doc: https://ionicframework.com/docs/storage/

here is my Code:

app-module.ts

    import { BrowserModule } from '@angular/platform-browser';
    import { ErrorHandler, NgModule } from '@angular/core';
    import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
    import { SplashScreen } from '@ionic-native/splash-screen';
    import { StatusBar } from '@ionic-native/status-bar';

    import { MyApp } from './app.component';
    import { HomePage } from '../pages/home/home';
    import { Intro } from '../pages/intro/intro';
    import { Checklist } from '../pages/checklist/checklist';
    // import { Http } from '@angular/http';
    import {IonicStorageModule} from '@ionic/Storage';
    import { Data } from '../providers/data';
    import {HttpModule} from '@angular/http';
    // import {Storage} from '@ionic/storage';


    @NgModule({
      declarations: [
        MyApp,
        HomePage,
        Intro,
        Checklist
      ],
      imports: [
        HttpModule,
        BrowserModule,
        IonicModule.forRoot(MyApp),
        IonicStorageModule.forRoot()
      ],
      bootstrap: [IonicApp],
      entryComponents: [
        MyApp,
        HomePage,
        Intro,
        Checklist
      ],
      providers: [
        StatusBar,
        SplashScreen,
        {provide: ErrorHandler, useClass: IonicErrorHandler},
        // Storage,
        //Http,
        Data
      ],
    })
    export class AppModule {}


data.ts

import { Injectable } from '@angular/core';
// import { Http } from '@angular/http';
import 'rxjs/add/operator/map';
// import { HttpModule } from '@angular/http';

import { Storage } from '@ionic/storage';


@Injectable()
export class Data {
  constructor(public storage: Storage) {
  }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  getData(): Promise<any> {
    return this.storage.get('checklists');
  }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  save(data): void {
    let saveData = [];
    //Remove observables
    data.forEach((checklist) => {
      saveData.push({
        title: checklist.title,
        items: checklist.items
      });
    });
    let newData = JSON.stringify(saveData);
    this.storage.set('checklists', newData);
  }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}

home.ts

// import { Component } from '@angular/core';
// import { NavController } from 'ionic-angular';

// @Component({
//   selector: 'page-home',
//   templateUrl: 'home.html'
// })
// export class HomePage {

//   constructor(public navCtrl: NavController) {

//   }

// }


import { Component } from '@angular/core';
import { NavController, AlertController, Platform } from 'ionic-angular';
import { Checklist } from '../checklist/checklist';
import { ChecklistModel } from '../../models/checklist-model';
import { Data } from '../../providers/data';
import { Keyboard } from 'ionic-native';
@Component({
  selector: 'page-home',
  templateUrl: 'home.html',
})
export class HomePage {
  checklists: ChecklistModel[] = [];

  constructor(public navCtrl: NavController, public dataService: Data,
    public alertCtrl: AlertController, public platform: Platform) {
  }

  // constructor(public navCtrl: NavController, public alertCtrl: AlertController, public platform: Platform) {
  //   // this.checklists.push(new ChecklistModel("Noam", [1,2,3]));
  // }
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  ionViewDidLoad() {
  }
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  addChecklist(): void {
    let prompt = this.alertCtrl.create({
      title: 'New Checklist',
      message: 'Enter the name of your new checklist below:',
      inputs: [
        {
          name: 'name'
        }
      ],
      buttons: [
        {
          text: 'Cancel'
        },
        {
          text: 'Save',
          handler: data => {
            let newChecklist = new ChecklistModel(data.name, []);
            this.checklists.push(newChecklist);
            newChecklist.checklistUpdates().subscribe(update => {
              this.save();
            });
            this.save();
          }
        }
      ]
    });
    prompt.present();
  }
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  renameChecklist(checklist): void {
    let prompt = this.alertCtrl.create({
      title: 'Rename Checklist',

      message: 'Enter the new name of this checklist below:',
      inputs: [
        {
          name: 'name'
        }
      ],
      buttons: [
        {
          text: 'Cancel'
        },
        {
          text: 'Save',
          handler: data => {
            let index = this.checklists.indexOf(checklist);
            if (index > -1) {
              this.checklists[index].setTitle(data.name);
              this.save();
            }
          }
        }
      ]
    });
    prompt.present();
  }
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  viewChecklist(checklist): void {
    this.navCtrl.push(Checklist, {
      checklist: checklist
    });
  }
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  removeChecklist(checklist): void {
    let index = this.checklists.indexOf(checklist);
    if (index > -1) {
      this.checklists.splice(index, 1);
      this.save();
    }
  }
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  save(): void {
    Keyboard.close();
    this.dataService.save(this.checklists);
  }
  ///////////////////////////////////////////////////////////////////////////////////////////////////////////
}

The method that is supposed to get called and use the Storage is HomePage's save().

I can't get that far, however, because before the page even loads, I get

Runtime Error Uncaught (in promise): Error: No provider for Storage! Error at g (http://localhost:8100/build/polyfills.js:3:7133) at injectionError (http://localhost:8100/build/main.js:1585:86) at noProviderError (http://localhost:8100/build/main.js:1623:12) at ReflectiveInjector_.throwOrNull (http://localhost:8100/build/main.js:3125:19) at ReflectiveInjector.getByKeyDefault (http://localhost:8100/build/main.js:3164:25) at ReflectiveInjector.getByKey (http://localhost:8100/build/main.js:3096:25) at ReflectiveInjector.get (http://localhost:8100/build/main.js:2965:21) at AppModuleInjector.get (ng:///AppModule/module.ngfactory.js:254:82) at AppModuleInjector.getInternal (ng:///AppModule/module.ngfactory.js:481:44) at AppModuleInjector.NgModuleInjector.get (http://localhost:8100/build/main.js:3929:44) at resolveDep (http://localhost:8100/build/main.js:11334:45) at createClass (http://localhost:8100/build/main.js:11202:32) at createDirectiveInstance (http://localhost:8100/build/main.js:11028:37) at createViewNodes (http://localhost:8100/build/main.js:12377:49) at createRootView (http://localhost:8100/build/main.js:12282:5)

Package.json:

{
  "name": "ionic-hello-world",
  "author": "Ionic Framework",
  "homepage": "http://ionicframework.com/",
  "private": true,
  "config": {
    "ionic_source_map": "source-map"
  },
  "scripts": {
    "clean": "ionic-app-scripts clean",
    "build": "ionic-app-scripts build",
    "ionic:build": "ionic-app-scripts build",
    "ionic:serve": "ionic-app-scripts serve"
  },
  "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/core": "3.4.2",
    "@ionic-native/splash-screen": "3.4.2",
    "@ionic-native/status-bar": "3.4.2",
    "@ionic/storage": "^2.0.1",
    "ionic-angular": "3.0.1",
    "ionic-native": "^2.9.0",
    "ionicons": "3.0.0",
    "rxjs": "5.1.1",
    "sw-toolbox": "3.4.0",
    "zone.js": "^0.8.4"
  },
  "devDependencies": {
    "@ionic/app-scripts": "1.3.0",
    "typescript": "~2.2.1",
    "webpack": "^2.4.1"
  },
  "cordovaPlugins": [
    "cordova-plugin-whitelist",
    "cordova-plugin-console",
    "cordova-plugin-statusbar",
    "cordova-plugin-device",
    "cordova-plugin-splashscreen",
    "ionic-plugin-keyboard"
  ],
  "cordovaPlatforms": [],
  "description": "quicklists: An Ionic project"
}

Since I did everything the doc said, please enlighten me - What is still missing that would cause the Storage not to be found

Thanks

Gulzar
  • 23,452
  • 27
  • 113
  • 201
  • In your app module, did you try moving the IonicStorageModule(forRoot) that's in your import statement to the providers array? It seems like that error is pointing in that direction pretty hard. Not sure if you need the forRoot part, but I'd try moving it out of the imports array and to the provider array. Pretty sure that's where injectable things need to go. – chairmanmow Apr 17 '17 at 22:26
  • 1
    @chairmanmow http://stackoverflow.com/questions/42788623/local-storage-in-ionic-2-error here it tells me to do what I did, Also the doc https://ionicframework.com/docs/storage/ states it belongs in imports – Gulzar Apr 17 '17 at 22:31
  • 1
    Hmm, yeah, I guess you followed the instructions. I did notice one thing that might be involved, I noticed that you're importing 'import { Storage } from '@ionic/storage';' one place, and your importing import { Storage } from '@ionic/Storage';... Note the S is capitalized in one of those. Anyways, not sure how much I can help, but maybe that's a typo. – chairmanmow Apr 17 '17 at 22:42

7 Answers7

33

EDIT

This answer used to get a lot of upvotes, and that stopped.

I can only assume this is due to version updates/bug fixes.

I suggest you update your angular before going forward with this solution.


Firstly you need to install: npm install --save @ionic/storage

The problem was in app.ts:

import {IonicStorageModule} from '@ionic/Storage';

Capital 'S' instead of non capital 's':

from '@ionic/Storage'

instead of:

from '@ionic/storage'

No idea why the compiler wouldn't catch that if it's a problem, but it didn't.

Thanks to @chairmanmow

Gulzar
  • 23,452
  • 27
  • 113
  • 201
  • https://github.com/ionic-team/ionic-storage/releases/tag/v2.0.0 Run npm install @ionic/storage@2.0.0 --save --save-exact Remove Storage from your providers in app.module.ts import { IonicStorageModule } from '@ionic/storage' instead of import { IonicStorage } from '@ionic/storage' in app.module.ts Add IonicStorageModule.forRoot() to the imports array in app.module.ts – JGFMK Aug 09 '17 at 21:34
  • 1
    **For me**, it was small `s` . It needs to be the same as present in your `package.json`. – nice_dev Apr 12 '19 at 10:05
16

In my case, I forgot to add the following in app.module.ts

import { IonicStorageModule } from '@ionic/storage';

@NgModul({ 
  ..., 
  Imports: [
  ...
    IonicStorageModule.forRoot()
],
Prashant Pimpale
  • 10,349
  • 9
  • 44
  • 84
VictorL
  • 379
  • 3
  • 5
10

first do this npm install --save @ionic/storage

I managed to get this working using this ..

Inside app.module.ts

import { Storage } from '@ionic/storage';

And then ...

providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}, Storage]

And then in my page.ts

import { Storage } from '@ionic/storage';

In the constructor ...

public storage: Storage

And then within the guts of my code ..

this.storage.get('date').then((value) => {
  // blah
});
Chris
  • 4,672
  • 13
  • 52
  • 93
  • Don't need to add `Storage` for `app.module.ts` file's `providers:` , which gives `Uncought error`. In my case I forgot to add `import { Storage } from '@ionic/storage';` at the `page.ts` component page. Thanks @Chris. – Tharusha Jan 08 '19 at 05:40
1

I had the same issue. I added this to app.module.ts:

import { IonicStorageModule } from '@ionic/storage';

And, this to imports parts of the app.module.ts:

IonicStorageModule.forRoot(),
Don Brody
  • 1,689
  • 2
  • 18
  • 30
0

2021 Ionic Storage v3 Angular:

import { IonicStorageModule } from '@ionic/storage-angular';
IonicStorageModule.forRoot(),
Daniel Ehrhardt
  • 908
  • 7
  • 16
0

I had the same problem. Please make sure that you remember to add the main module in your app.module.ts file

import { IonicStorageModule } from '@ionic/storage';

@NgModule({ 
  ..., 
  Imports: [
    ...
    IonicStorageModule.forRoot()
  ],
  ....
})

And also make sure that you are actually importing the actual Storage from @ionic/storage-angular.

constructor(private storage: Storage) { }

The above will seem fine and not show any errors even if you dont include

import { Storage } from '@ionic/storage-angular'

at the top of your file. I presume that is because of the native Storage available on the global window object.

davejoem
  • 4,902
  • 4
  • 22
  • 31
0

The injection as explained in the doc (https://github.com/ionic-team/ionic-storage), works well;

I first missed this information: "this approach is meant for usage in a single component", so, using it for both AppComponent and HomePage I did get this error, exactly.

I restored app.component.ts in its previous state, and all is fine now. (works on ionic 6.20.1)

tontonCD
  • 320
  • 2
  • 6