Ionic Storage (Ionic 8, Angular 17) error: `ERROR NullInjectorError: NullInjectorError: No provider for Storage`

I am currently encountering challenges in integrating Ionic Storage within my Ionic 8 (Angular 17) application.

I have adhered to the official documentation guidelines for implementing Ionic Storage within an independent service. The following is the content of the storage.service.js file:

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root',
})
export class StorageService {
  private _storage: Storage | null = null;

  constructor(private storage: Storage) {
    this.init();
  }

  async init() {
    const storage = await this.storage['create']();
    this._storage = storage;
  }

  public async get(key: string) {
    const value = await this._storage?.['get'](key);

    return value;
  }

  public async set(key: string, value: any) {
    await this._storage?.['set'](key, value);
  }
}

I am utilizing this service within another service for authentication-related purposes. The following is the content of the auth.service.js file:

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { StorageService } from './storage.service';

interface Credentials {
  username: string;
  password: string;
}

export interface AuthResponse {
  auth_token: string;
}

@Injectable({
  providedIn: 'root',
})
export class AuthService {
  constructor(
    private httpClient: HttpClient,
    private storageService: StorageService
  ) {}

  async getAuthToken(): Promise<string> {
    const token = await this.storageService.get('token');

    return token;
  }

  async isAuthenticated(): Promise<boolean> {
    const token = await this.getAuthToken();

    if (token) {
      return true;
    }

    return false;
  }

  authenticate(credentials: Credentials): Observable<AuthResponse> {
    return this.httpClient.post<AuthResponse>(
      `${import.meta.env['NG_APP_API_BASE_URL']}/${
        import.meta.env['NG_APP_API_PREFIX']
      }/token/login`,
      credentials
    );
  }

  async processPostLoginOps(token: string): Promise<void> {
    await this.storageService.set('token', token);

    const authenticated = await this.isAuthenticated();

    if (authenticated) {
      throw new Error('Unable to login');
    }
  }
}

Finally I am integrating this service within a page. The following is the content of the login.page.ts file:

import { CommonModule } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import {
  FormBuilder,
  FormGroup,
  FormsModule,
  ReactiveFormsModule,
  Validators,
} from '@angular/forms';
import { Router } from '@angular/router';
import {
  IonButton,
  IonCard,
  IonCardContent,
  IonCol,
  IonContent,
  IonGrid,
  IonHeader,
  IonInput,
  IonItem,
  IonList,
  IonNav,
  IonRow,
  IonTitle,
  IonText,
  IonToolbar,
} from '@ionic/angular/standalone';
import { LoadingController, ToastController } from '@ionic/angular';
import { AuthService, AuthResponse } from 'src/app/services/auth.service';
import { Capacitor } from '@capacitor/core';

@Component({
  selector: 'app-login',
  templateUrl: './login.page.html',
  styleUrls: ['./login.page.scss'],
  standalone: true,
  imports: [
    IonButton,
    IonCard,
    IonCardContent,
    IonCol,
    IonContent,
    IonGrid,
    IonHeader,
    IonInput,
    IonItem,
    IonList,
    IonNav,
    IonRow,
    IonTitle,
    IonText,
    IonToolbar,
    CommonModule,
    FormsModule,
    ReactiveFormsModule
  ],
})
export class LoginPage implements OnInit {
  form!: FormGroup;
  disabled: boolean = true;
  loadingOverlay!: HTMLIonLoadingElement;
  errorToast!: HTMLIonToastElement;

  constructor(
    private router: Router,
    private formBuilder: FormBuilder,
    private loadingController: LoadingController,
    private toastController: ToastController,
    private authService: AuthService
  ) {}

  async ngOnInit(): Promise<void> {
    this.initForm();
    this.subscribeToFormChanges();
    await this.setOrResetLoadingOverlay();
    await this.setToasts();
  }

  private async setToasts() {
    this.errorToast = await this.toastController.create({
      duration: 1500,
      position: 'bottom'
    });
  }

  private async setOrResetLoadingOverlay() {
    this.loadingOverlay = await this.loadingController.create({});
  }

  initForm(): void {
    this.form = this.formBuilder.group({
      username: ['', Validators.required],
      password: ['', Validators.required],
    });
  }

  subscribeToFormChanges(): void {
    this.form.statusChanges.subscribe((status) => {
      if (status === 'VALID') {
        this.disabled = false;
      } else {
        this.disabled = true;
      }
    });
  }

  async authenticate() {
    this.loadingOverlay.message = 'Logging in';
    await this.loadingOverlay.present();

    this.authService
      .authenticate({
        username: this.form.value.username,
        password: this.form.value.password,
      })
      .subscribe({
        next: async (response: AuthResponse) => {
          this.loadingOverlay.dismiss();
          this.loadingOverlay.message = 'fdnfgnfgn';
          this.loadingOverlay.present();

          try {
            this.authService.processPostLoginOps(response.auth_token);

            this.router.navigate(['/']).then(() => window.location.reload());
          } catch (error) {
            await this.setOrResetLoadingOverlay();
            
            this.errorToast.message = 'Unable to login';
            this.errorToast.present();
          }
        },
        error: async (error: any) => {
          this.loadingOverlay.dismiss();
          await this.setOrResetLoadingOverlay();

          this.errorToast.message = 'Unable to login';
          this.errorToast.present();
        },
      });
  }

  register(): void {
    this.router.navigate(['/register']);
  }
}

I am encountering the following error in my browser console: ERROR NullInjectorError: NullInjectorError: No provider for Storage!, upon attempting to configure Ionic Storage within Ionic 8 (Angular 17). Any guidance on the correct setup procedure would be greatly appreciated. Thank you in advance.

I am not an Angular user, but looking at the Angular specific documentation, did you initialize IonicStorageModule in NgModule?

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

@NgModule({
  imports: [
    IonicStorageModule.forRoot()
  ]
})
export class AppModule { }

I inadvertently overlooked this step. However, upon recognizing the error and rectifying it, the functionality was restored. Thank you.

1 Like

Hi Tirth,

Can you please show where you added the IonicStorageModule.forRoot()?

I am also facing this issue.
I am working on a standalone Angular project which does not have any NgModules.

Where should I provide IonicStorageModule.forRoot() in a standalone Angular project?

I got the answer for this in the below links.
Solutions in both the links are working for me.

Update README for Angular users · Issue #318 · ionic-team/ionic-storage (github.com)

ERROR Error: Uncaught (in promise): NullInjectorError: R3InjectorError(AppModule)[AuthGuard → StorageService → Storage → Storage]: NullInjectorError: No provider for Storage! · Issue #308 · ionic-team/ionic-storage (github.com)