J'ai une page de paramètres où les utilisateurs peuvent enregistrer certaines variables de configuration, telles qu'un nom d'utilisateur. L'utilisateur peut également changer le nom d'utilisateur sur cette page. Mais lorsque je vais dans un autre composant (page) et retour, le nom d'utilisateur n'est pas enregistré.
Je veux aussi montrer le nom d'utilisateur dans les autres composants. Comment je fais ça? Avec une variable globale?
Structure: - App - app.ts (main) - setting.ts - someOtherComponent.ts
Ce dont vous avez besoin, c'est d'un service pour maintenir l'état de vos variables. Vous pourrez alors injecter ce service dans n’importe quel composant pour définir ou obtenir cette variable.
Voici un exemple (/services/my.service.ts):
import {Injectable} from "angular2/core";
@Injectable()
export class MyService {
private myValue;
constructor() {}
setValue(val) {
this.myValue = val;
}
getValue() {
return this.myValue ;
}
}
Vous voudrez probablement mettre ce service dans le tableau des fournisseurs de la fonction d'amorçage de votre application (qui peut se trouver dans le fichier de composant de votre application principale ou dans un fichier séparé, en fonction de la manière dont vous aimez faire les choses).
Dans votre fichier d'application principal (/app.ts):
import {MyService} from './services/my.service';
bootstrap(App, [MyService, COMMON_DIRECTIVES, ROUTER_DIRECTIVES, ROUTER_PROVIDERS, HTTP_PROVIDERS]); // directives added here are available to all children
Vous n'avez pas besoin de COMMON_DIRECTIVES ni des autres éléments tout en majuscules du tableau, mais ceux-ci sont généralement inclus simplement pour que vous n'ayez pas à les configurer dans chaque composant que vous écrivez.
Ensuite, vous accéderiez au service à partir d'un composant tel que (/components/some-component.ts):
import {MyService} from '../services/my.service';
@Component({
selector: 'some-component',
template: `
<div>MyValue: {{val}}</div>
`
})
export class SomeComponent {
constructor(private myService:MyService) {
}
get val() {
return this.myService.getValue();
}
}
Vous pouvez également vouloir ajouter au service afin qu'il enregistre la valeur dans un emplacement (semi) permanent afin de pouvoir y accéder la prochaine fois que l'utilisateur entrera dans l'application.
Votre situation actuelle est peut-être exagérée, mais si vous envisagez d'agrandir votre application, vous éviterez de nombreux problèmes. Cela dit, je pense qu'Annular avec un magasin de type Redux est une combinaison très puissante. Ma suggestion est d'utiliser le module ngrx/store
.
Gestion des états basée sur RxJS pour les applications angulaires, inspirée de Redux
Source: ngrx/store
GitHub repo
Le code ci-dessous doit décrire toutes les étapes à suivre pour intégrer le ngrx/store
à votre application. Par souci de brièveté, j'ai omis tout code existant que vous pourriez avoir et toutes les importations que vous devrez ajouter.
Installer le module
npm install --save ngrx/core ngrx/store
Créer un réducteur
export const SETTINGS_UPDATE = 'SETTINGS_UPDATE';
const initialState = {
username: ''
};
export function settingsReducer(state: Object = initialState, action: Action) {
switch (action.type) {
case SETTINGS_UPDATE:
return Object.assign({}, state, action.payload);
default:
return state;
}
};
Importer le StoreModule
@NgModule({
imports: [
// your other imports
StoreModule.provideStore({
settings: settingsReducer
})
]
})
export class AppModule {
//
}
Créer une interface pour le réducteur de paramètres
export interface SettingsStore {
username: string;
}
Créer une interface de magasin
export interface AppStore {
settings: SettingsStore;
}
Créer un service de paramètres
@Injectable()
export class SettingsService {
settings$: Observable<SettingsStore>;
constructor(private store: Store<AppStore>) {
this.settings$ = this.store.select('settings');
}
public update(payload) {
this.store.dispatch({ type: SETTINGS_UPDATE, payload });
}
}
Paramètres Component Controller
@Component({
...
})
export class SettingsComponent implements OnInit {
settings$: Observable<SettingsStore>;
constructor(private settingsService: SettingsService) {
//
}
ngOnInit() {
this.settings$ = this.settingsService.settings$;
}
public updateUsername() {
this.settingsService.update({ username: 'newUsername' });
}
}
Modèle de composant de paramètres
<p *ngIf="(settings$ | async)?.username">
<strong>Username:</strong>
<span>{{ (settings$ | async)?.username }}</span>
</p>
<button (click)="updateUsername()">Update Username</button>
Avec la configuration décrite ci-dessus, vous pouvez ensuite injecter la SettingsService
dans n’importe quel composant et afficher la valeur dans son modèle.
De la même manière, vous pouvez également mettre à jour la valeur de store
à partir de n’importe quel composant en utilisant this.settingsService.update({ ... });
. Le changement sera répercuté sur tous les emplacements qui utilisent cette valeur - qu’il s’agisse d’un composant via un canal async
ou d’un autre service via .subscribe()
.
Vladimir a correctement mentionné à propos de ngrx
.
J'utiliserais un service avec Subject
BehaviourSubject
et Observable
à set
et get
l'état (valeurs) dont j'ai besoin.
Nous avons discuté ici Communication entre plusieurs composants avec un service en utilisant Observable et Subject dans Angular 2 comment partager des valeurs dans plusieurs composants sans relation parent
-child
ou child
-parent
et _/sans bibliothèque en tant que magasin ngrx
.
Vous auriez besoin d’un service pour pouvoir vous injecter partout où vous en avez besoin:
@Injectable()
export class GlobalService{
private value;
constructor(){
}
public setValue(value){
this.value = value;
}
public getValue(){
return this.value;
}
}
Vous pouvez fournir ce service dans tous vos modules, mais il est possible que vous obteniez plusieurs instances. Par conséquent, nous ferons du service un singleton.
@NgModule({
providers: [ /* DONT ADD THE SERVICE HERE */ ]
})
class GlobalModule {
static forRoot() {
return {
ngModule: GlobalModule,
providers: [ GlobalService ]
}
}
}
Vous ne devez appeler la méthode forRoot
que dans votre AppModule
:
@NgModule({
imports: [GlobalModule.forRoot()]
})
class AppModule {}
J'ai le même problème, la plupart des composants ont besoin d'informations logInUser ..__ Par exemple: nom d'utilisateur, langue préférée, fuseau horaire préféré de l'utilisateur, etc.
Donc pour cela, une fois que l'utilisateur se connecte, on peut faire ce qui suit:
Si toutes les informations sont dans JWT Token ou/me RESTful Api, vous pouvez alors décoder le jeton dans l'un des services.
par exemple: user.service.ts
@Injectable()
export class UserService {
public username = new BehaviorSubject<string>('');
public preferredLanguage = new BehaviorSubject<string>('');
public preferredTimezone = new BehaviorSubject<string>('');
constructor(
private router: Router,
private jwtTokenService: JwtTokenService
) {
let token: string = localStorage.getItem('token'); // handled for page hard refresh event
if (token != null) {
this.decode(token);
}
}
private decode(token: string) {
let jwt: any = this.jwtTokenService.decodeToken(token);
this.username.next(jwt['sub']);
this.preferredLanguage.next(jwt['preferredLanguage']);
this.preferredTimezone.next(jwt['preferredTimezone']);
}
public setToken(token: any) {
localStorage.setItem('auth_token', token);
this.decode(token);
}
}
qui détient trois sujets de comportement publics, quiconque écoute cette variable obtiendra la valeur si elle change. Veuillez vérifier le style de programmation de rxjs.
et maintenant, partout où cette variable est requise, il suffit de s’abonner à ce composant.
Par exemple: NavComponent aura certainement besoin d'un nom d'utilisateur. le code va donc ressembler à ceci ci-dessous:
export class NavComponent implements OnInit {
public username: string;
constructor(
private userService: UserService,
private router: Router) {
}
ngOnInit() {
this.userService.username.subscribe(data => {
this.username = data;
});
}
}
Par conséquent, programmation réactive donne une meilleure solution pour gérer la variable de dépendance.
Ce qui précède résout également le problème si l'actualisation de la page est difficile, car je stocke la valeur dans localstorage et la récupère dans le constructeur.
Remarque: il est supposé que les données utilisateur enregistrées proviennent de jetons JWT. Nous pouvons également utiliser le même service (UserHttpService) si les données proviennent de Restful Api. Par exemple: api/moi