Ionic 4 Service variables do not change their values

Hi all,

I use a Service to make the login system I use an object to keep username, token, and the password. I save the values on LaginPage in the object from the service.

AuthService

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class AuthService {

 public credentials = {
  username:'',
  password:'',
  token:''
} 
  constructor(public http:HttpClient) { }

LoginPage.html

<ion-content padding>
  <ion-item>
    <ion-label>
      <ion-icon name="mail"></ion-icon>
    </ion-label>
    <ion-input clearInput placeholder="Username" type="text" [(ngModel)]="this.authService.credentials.username"></ion-input>
  </ion-item>
  <ion-item>
    <ion-label>
      <ion-icon name="lock"></ion-icon>
    </ion-label>
    <ion-input clearInput placeholder="Password" type="password" [(ngModel)]="this.authService.credentials.password"></ion-input>
  </ion-item>
  <ion-button padding expand="full" color="nicedarkgreen" (click)="Login()">Login</ion-button>
</ion-content>

LoginPage.ts

import { Component, OnInit } from '@angular/core';
import { NavController, AlertController } from '@ionic/angular';
import { Router } from '@angular/router';
import { Storage } from '@ionic/storage';

import { AuthService } from '../../services/auth.service';

@Component({
  selector: 'app-login',
  templateUrl: './login.page.html',
  styleUrls: ['./login.page.scss'],
})
export class LoginPage implements OnInit {

  constructor(public navCtrl: NavController, public routsCtrl:Router, public authService:AuthService,public storage: Storage,
    private alertCtrl: AlertController,private ordersService:OrdersService) { }

  ngOnInit(){
    if(!this.authService.credentials.username)
    {
    this.storage.get('username').then((val) => {
      if(val)
      {
          this.authService.credentials.username = val;
          this.storage.get('password').then((val) => {
            if(val)
            {
                this.authService.credentials.password = val;
            }
        });
      }
      });
    }
    console.log(this.authService.credentials);
  }

Login()
  {
      let newCredentials;
      if(!this.authService.credentials.username || !this.authService.credentials.password)
      {
        this.PresentAlert('Missing username or password','Enter the username and the password.');
      }else{
        newCredentials = {"username":this.authService.credentials.username,"password":this.authService.credentials.password
      };
        this.storage.set('username',this.authService.credentials.username);
        this.storage.set('password',this.authService.credentials.password);
      }
      this.authService.Login(newCredentials).then(()=>{
          if(this.authService.canActivate())
          {
            this.storage.set('token', this.authService.credentials.token);
            console.log(this.authService.credentials);
            this.ordersService.PresentLoadingDefault();
            this.ordersService.GetOrders().then(()=>
            {
              this.ordersService.GetArchive().then(()=>{
                this.routsCtrl.navigateByUrl('/tabs/dashboard/(home:home)');
                this.ordersService.loading.dismiss();
            });
            });
          }else
          {
            this.routsCtrl.navigate(['login'])
          }
      },(err) =>{
      });
  }

14
On LoginPage I can view the correct values for “credentials” but when I access the values on a different page it returns the default value which is a blank string.
42%20copy

I’m going to give you a bunch of rules that may initially seem arbitrary, but if you follow them you will become immune to bugs like this one:

First, and most importantly, never store passwords. Anywhere.

Never use Storage for in-app communication, only for speaking to the next app run and listening to the last.

Therefore:

  • never interact directly with Storage in pages, only in services
  • only read from Storage once, at service construction
  • either accept that your writes to Storage are optimistic (generally OK) or be prepared to always follow up on the Promise that set gives you

If data stored in services can change for any reason, and you care about not using stale data (which is virtually always the case for authentication information like this), never expose it as raw data (such as authService.credentials), only as futures (Promises or Observables). Subjects can be helpful here.

2 Likes

Thanks for the advice, but I found the issue:). I have set services in the page module, not in the app module.

1 Like

Bookmark this page anyway, because you probably still have a race condition that will bite you at some point.

thanks, it save my day.

Then what do you suggest to keep the email _angularFireAuth.auth.currentUser.email) available in any pages ( component, service,…) of the app if you suggest to not use Storage?

interface Profile {
  id: string;
  email: string;
  ...
}

class ProfileService {
  activeUser$ = new BehaviorSubject<Profile | undefined>();

  updateActiveUser(profile: Profile): void {
    this.activeUser$.next(profile);
  }
  
  peekActiveUser(): Profile | undefined {
    return this.activeUser$.value;
  }

  watchActiveUser(): Observable<Profile | undefined> {
    return this.activeUser$;
  }
}
2 Likes