skip to Main Content

I am struggling with creating a feature in my Angular 14 an Ionic 6 app. I wish to make an “Welcome” screen in my app that appears only the first time that the user has opened an app and then never again.

I don’t know how to save that state that the users screen has already been seen by the user and the app should not load it upon second time opening the app…

My idea was to make a storage service that saves the state and then have a route guard that handles redirection and page showing…

I am now receiving this error and have no idea how to fix it… Am I ever corectly storing the value in the storage service or is my code totely wrong?
ERROR:

Error: src/app/guards/first-load.guard.ts:17:50 – error TS2339:
Property ‘then’ does not exist on type ‘void’. [ng] [ng] 17
this.storageService.getValue(‘first_time’).then((value) => { [ng]

My code is bellow:

storage.service.ts:

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

  async init() {
    await this.storage.create();
  }
  setValue(key: 'first_time', value: 'done') {
    this.storage.set(key, value);
  }

  getValue(key: 'first_time') {
    this.storage.get(key).then((value) => {
      console.log(value);
    });
  }
}

and here in the first-load.guard.ts I am calling this service:

export class FirstLoadGuard implements CanActivate {
  constructor(
    private storageService: StorageService,
    private router: Router
  ) {}
  canActivate(route: ActivatedRouteSnapshot):  Promise<boolean>
  {
    return new Promise(resolve => {
      this.storageService.getValue('first_time').then((value) => {
        if (value !== null) {
          this.router.navigateByUrl('/login');
          resolve(false);
        }
        else {
          this.storageService.setValue('first_time', 'done');
          resolve(true);
        }
      });
    });
  }
}

If I need to provide more code feel free to just leave me a comment 🙂 I wish someone could help me

2

Answers


  1. you have problem in your functions definitions. : is for declaring format, you are defining variables as constants and that’s probably why you are getting null.

    change
    key: 'first_time' and value: 'done' in your storage service to key: string and value: string. or if you want to have a default value for your functions input:

    getValue(key: string = 'first_time')
    

    or if your inputs are really constant and are not inputs at all, you’d better define them in your service instead of taking inputs:

    key= 'first_time';
    value= 'done';
    setValue() {
        this.storage.set(this.key, this.value);
      }
    
    getValue() {
        this.storage.get(this.key).then((value) => {
          console.log(value);
        });
      }
    
    Login or Signup to reply.
  2. The reason you get the error message

    Error: src/app/guards/first-load.guard.ts:17:50 – error TS2339: Property ‘then’ does not exist on type ‘void’. [ng] [ng] 17
    this.storageService.getValue(‘first_time’).then((value) => { [ng]

    is because your storageService.getValue() does not actually return anything. To fix this error you need to return the promise with the value from the storage:

      getValue(key: 'first_time') {
        return this.storage.get(key).then((value) => {
          console.log(value);
          return value;
        });
      }
    

    If you can drop the console.log() it can be shorter:

      getValue(key: 'first_time') {
        return this.storage.get(key);
      }
    

    Additionally some more comments on your code:

    As @AmirAli Saghaei wrote in the other answer you’re currently declaring the types of the function arguments as static values, i.e., calling setValue() with any other argument values as first_time and done would give you a type error while compiling. This is most probably not what you want.

    If you wanted to provide default values for the arguments use = instead of ::

      setValue(key = 'first_time', value = 'done') {
        // ...
      }
    

    If you want to specify the expected type you should use string:

      setValue(key: string, value: string) {
        // ...
      }
    

    Since init() is only called synchronously by the constructor it makes no difference using async/await here. You would have to await it in the constructor for which the constructor would have to return a promise – which is a bad practice.

    In the route guard you don’t need to create a new Promise() but you can just chain and return the promise from getValue:

      canActivate(route: ActivatedRouteSnapshot): Promise<boolean>
      {
        return this.storageService.getValue('first_time').then((value) => {
          if (value !== null) {
            this.router.navigateByUrl('/login');
            return false;
          }
          else {
            this.storageService.setValue('first_time', 'done');
            return true;
          }
        });
      }
    

    Or using async / await:

      async canActivate(route: ActivatedRouteSnapshot): Promise<boolean>
      {
        const value = await this.storageService.getValue('first_time');
        if (value !== null) {
          this.router.navigateByUrl('/login');
          return false;
        }
        else {
          this.storageService.setValue('first_time', 'done');
          return true;
        }
      }
    

    So a more simplified version of your code could be:

    export class StorageService {
      constructor(
        private storage: Storage
      ) {
        this.storage.create();
      }
    
      setValue(key: string, value: string) {
        this.storage.set(key, value);
      }
    
      getValue(key: string) {
        return this.storage.get(key);
      }
    }
    
    
    export class FirstLoadGuard implements CanActivate {
      constructor(
        private storageService: StorageService,
        private router: Router
      ) {}
    
      async canActivate(route: ActivatedRouteSnapshot): Promise<boolean>
      {
        const value = await this.storageService.getValue('first_time');
        if (value !== null) {
          this.router.navigateByUrl('/login');
          return false;
        }
        else {
          this.storageService.setValue('first_time', 'done');
          return true;
        }
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search