1
votes

Comment partager des données entre les services et les composants angular?

Comment lier des données entre des services et des composants en temps réel.

Supposons que isAuthenticated une variable publique pour le service d'authentification qui affecte une vue dans un composant. Ma question est de savoir comment souscrire à la variable isAuthenticated ?

Service:

...
<div *ngIf="authService.isAuthenticated">Authentication view</div>
<div *ngIf="!authService.isAuthenticated">Unauthentication view</div>
...

Composant:

...
<div *ngIf="isAuthenticated">Authentication view</div>
<div *ngIf="!isAuthenticated">Unauthentication view</div>
...

home.html

...
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
private isAuthenticated:boolean = false;
  constructor(public authService: Authentication) { 
   this.isAuthenticated = this.authService.isAuthenticated'
  }
}

Selon le flux actuel ci-dessus, la liaison fonctionne bien mais n'est pas en temps réel.

Quelle est donc la meilleure approche:

1- Créez un observable à l'intérieur du service d'authentification afin de vous y abonner à l'intérieur du composant.

2- Liaison de la manière suivante:

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

@Injectable()
export class Authentication {

  isAuthenticated:boolean = false;

  login() {
    localStorage.setItem('access_token', 'true');
    this.isAuthenticated = true;
  }
}

La deuxième approche fonctionne bien mais je ne sais pas si c'est la meilleure pratique.

Merci.


1 commentaires

N'exécutez pas de requêtes depuis un constructeur (c.-à-d. Appelez votre service pour vérifier isAuthenticated). Implémentez OnInit à la place sur votre composant et faites-le là.


4 Réponses :


0
votes

Je suppose d'après votre balise que vous utilisez le framework Ionic? Cela peut-il être fait à l'aide d'événements?

    // first page (publish an event when a user is created)
constructor(public events: Events) {}
createUser(user) {
  console.log('User created!')
  this.events.publish('user:created', user, Date.now());
}


// second page (listen for the user created event after function is called)
constructor(public events: Events) {
  events.subscribe('user:created', (user, time) => {
    // user and time are the same arguments passed in `events.publish(user, time)`
    console.log('Welcome', user, 'at', time);
  });
}

Exemple de code extrait de: https://ionicframework.com/docs/v3/api/util/Events/


3 commentaires

est-il possible de créer l'événement dans un fournisseur (service)?


Cela devrait être possible, mais je ne suis pas sûr que ce soit la meilleure pratique, comment appelle-t-on la méthode "login"? Cela pourrait être changé pour qu'il renvoie une observable ou une promesse, puis à partir de cet appel l'événement Ionic (en supposant que l'appelant ne soit pas sur la même page que celle à partir de laquelle vous appelez "login", auquel cas l'événement ne serait pas nécessaire ).


Je ne pense pas que vous puissiez changer la valeur de l'événement comme ... next (false) ou quelque chose comme ça



3
votes

Je recommanderais d'utiliser BehaviorSubject . C'est un Observable , vous pouvez donc vous y abonner, mais vous pouvez également contrôler quand il émet de nouvelles valeurs en appelant behaviorSubject.next (newValue) . Lors de la création de BehaviorSubject, vous devez lui transmettre la valeur initiale. Dans votre cas, c'est false.

<div *ngIf="isAuthenticated | async">Authentication view</div>
<div *ngIf="!(isAuthenticated | async)">Unauthentication view</div>

-

export class HomePage {

  private isAuthenticated: BehaviorSubject<boolean>;

  constructor(public authService: Authentication) { 
   this.isAuthenticated = this.authService.isAuthenticated;
  }

}

ou vous pouvez vous abonner en html avec Async Pipe

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

  private isAuthenticated:boolean;

  constructor(public authService: Authentication) { 
   this.authService.isAuthenticated
    .subscribe(isAuthenticated => this.isAuthenticated = isAuthenticated)
  }

}

-

@Injectable()
export class Authentication {

  isAuthenticated = new BehaviorSubject<boolean>(false);

  login() {
    localStorage.setItem('access_token', 'true');
    this.isAuthenticated.next(true);
  }

}

Contrairement à Observable classique, lorsque vous appelez subscribe sur BehaviorSubject, la fonction que vous avez passée en argument pour vous abonner sera immédiatement exécuté. En effet, BehaviorSubject a toujours une valeur. Vous pouvez y accéder avec this.authService.isAuthenticated.value mais ce n'est pas très utile ici.


3 commentaires

Comment importer BehaviorSubject?


quelle version de RxJS utilisez-vous?


pour RxJS v6 + vous pouvez l'importer comme ceci import {BehaviorSubject} depuis 'rxjs';



0
votes

Utilisez RXJS. L'utilisation de BehaviourSubjects vous permet de pousser l'état et de vous abonner aux changements d'état dans plusieurs composants qui injectent le service et ont un état initial. Lors de la définition d'un BehaviourSubject, vous devez également définir une valeur de départ qui est ici false. Tout ce que vous avez à faire est d'appeler .next (true) sur l'état BehaviourSubject to push comme indiqué ci-dessous:

...
@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage implements OnInit {
  private isAuthenticated:boolean = false;
  private readonly _authService: Authentication;
  constructor(authService: Authentication) {
    this._authService = authService;
  }

  public ngOnInit(): void {
   this._authService.isAuthenticated
     .subscribe((isAuthenticated) => this.isAuthenticated = isAuthenticated)
  }
}

L'utilisation d'une méthode get sur votre service vous permet de retourne une observable sans exposer publiquement les méthodes sur le BehaviourSubject.

Puis dans votre composant:

...
@Injectable()
export class Authentication {

  private _isAuthenticated: BehaviourSubject<boolean> = new BehaviourSubject(false);

  public get isAuthenticated(): Observable<boolean> {
    return this._isAuthenticated.asObservable();
  }

  login() {
    localStorage.setItem('access_token', 'true');
    this._isAuthenticated.next(true);
  }
}


0 commentaires

0
votes

Pour le moment, j'utilise cette solution:

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

//...

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  private isAuthenticated:boolean = false;
  constructor(public authService: Authentication) { }

  ngDoCheck() {
      if (this.authService.isAuthenticated)) {
        //..if authenticated do this
      } else {
        //..if not do this
      }
  }
}

Même si je ne suis pas sûr que ce soit une bonne solution.


0 commentaires