web-dev-qa-db-fra.com

Actualiser l'en-tête après la connexion dans Angular2

J'ai donc un composant d'en-tête qui affiche soit le nom de l'utilisateur ou "Se connecter" selon qu'ils sont connectés ou non. J'ai également un composant de connexion qui fait toute la logique commerciale de la connexion. Ils n'ont actuellement pas de relation parent/enfant.

Lorsque l'utilisateur se connecte, l'en-tête n'est ni actualisé ni modifié, sauf si une actualisation de page complète est effectuée dans le navigateur. J'ai fait beaucoup de recherches et de lectures en ligne sur différentes façons de procéder. ngOnChanges, NgZone, ApplicationRef et ChangeDetectorRef semblent être les plus populaires. J'essaie d'implémenter ce comportement dans ChangeDetectorRef car cela semble être le plus pertinent pour ma situation. Cependant, je n'arrive pas à trouver des exemples réels de la façon d'utiliser cela.

Je l'ai codé, mais il ne semble rien faire. Tout avis sera le bienvenu. J'accepterais même que je prenne la mauvaise approche et que je dois utiliser une autre solution que ChangeDetectorRef.

LoginComponent

import { Component, OnInit } from '@angular/core';
import { Response } from '@angular/http';
import { Router } from '@angular/router';

import { AuthenticationService } from '../service/authentication.service';

@Component({
    selector: 'login-component',
    templateUrl: './login.component.html'
})

export class LoginComponent implements OnInit {
    constructor(private router: Router, 
                private authenticationService: AuthenticationService) { }

    ngOnInit() {
        // Resets the login service.  
        // This is one of the events that should cause the refresh.
        this.authenticationService.logout();
    }

    login() {
        /*
        Authentication code
        This is the other event that should cause the refresh.
        */
    }
}

HeaderComponent

import { ChangeDetectorRef, ChangeDetectionStrategy, Component, OnInit } from '@angular/core';

import { Instance } from '../../entity/instance';

@Component({
    selector: 'header-component',
    templateUrl: './html/header.component.html',
    changeDetection: ChangeDetectionStrategy.OnPush
})

export class HeaderComponent {

    userName: string;

    constructor(private ref: ChangeDetectorRef) {
        this.ref.markForCheck();
    }

    ngOnInit(): void {
        var currentUser = JSON.parse(localStorage.getItem('currentUser'));

        this.userName = currentUser && currentUser.full_name;

        if (!this.userName) {
            this.userName = "User Name";
        }
    }
}

AppComponent

import { ChangeDetectorRef, ChangeDetectionStrategy, Component, OnInit } from '@angular/core';

import { Instance } from './entity/instance';
import { InstanceService } from './service/instance.service';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css'],
    changeDetection: ChangeDetectionStrategy.OnPush
})

export class AppComponent implements OnInit {

    instances: Instance[];

    constructor(private instanceService: InstanceService) { }

    ngOnInit(): void {
    }
}

app.component.html

<header-component></header-component>

<router-outlet></router-outlet>
14
Pinski

J'ai donc fini par suivre certains des conseils d'utilisation de mon service pour émettre le changement. J'ai lu à certains endroits sur Stack Overflow que l'utilisation d'un service de cette façon était un mauvais modèle, que les émissions ne devraient se produire qu'à partir d'un composant enfant vers un composant parent. Je ne suis donc pas sûr que ce soit la "bonne" façon, mais cela fonctionne pour moi car je veux que plusieurs composants connaissent cet événement.

J'avais déjà un service qui s'occupait de mon authentification, donc tout ce que j'avais à faire était de lui donner un émetteur, d'émettre au bon moment, puis d'écouter l'émission dans mon composant.

Composant d'en-tête

export class HeaderComponent {
    userName: string;

    constructor(private authenticationService: AuthenticationService) {
        authenticationService.getLoggedInName.subscribe(name => this.changeName(name));
    }

    private changeName(name: string): void {
        this.userName = name;
    }
}

Service d'authentification

@Injectable()
export class AuthenticationService {
    @Output() getLoggedInName: EventEmitter<any> = new EventEmitter();

    login(email: string, password: string): Observable<boolean> {
        if (successfulLogIn(email, password)) {
            this.getLoggedInName.emit(fullName);
            return true;
        } else {
            this.getLoggedInName.emit('Sign In');
            return false;
        }
    }

    logout(): void {
        this.getLoggedInName.emit('Sign In');
    }
}
18
Pinski

@Pinski était bon. Mais cela peut être plus simple. Il s'agit d'une méthode alternative pour émettre et souscrire des données.

Composant d'en-tête

export class HeaderComponent implements OnInit {
    userName: string;

    constructor(private authenticationService: AuthenticationService) {}

   NgOnInit() {
      this.authenticationService.getLoggedInName.subscribe(name => this.userName = name);
   }

}

Service d'authentification

@Injectable()
export class AuthenticationService {
    public getLoggedInName = new Subject(); //Alternate method to Emitting data across Components. Subject() is doing both Emitting data and Subscribing it in another component. So its the best way to compare with Emitting using Output.

    login(email: string, password: string): Observable<boolean> {
        if (successfulLogIn(email, password)) {
            this.getLoggedInName.next(fullName); //next() method is alternate to emit().
            return true;
        } else {
            this.getLoggedInName.next('Sign In');
            return false;
        }
    }

    logout(): void {
        this.getLoggedInName.next('Sign In');
    }
}

Essayez de Subject () . Codage heureux.

7
silambarasan R.D

Vous pouvez le faire ->

Composant d'en-tête ->

 ngOnInit() {
this.subscription = this.emitterService.getEmitter('userDetails').subscribe((user: Object) => {
            if(user)
                this.userName = user["name"];
        });
    }
ngOnDestroy() {
        // prevent memory leak when component is destroyed
        this.subscription.unsubscribe();
    }

Service de connexion ->

this.emitterService.getEmitter('userDetails').emit(userDetails);

la valeur que vous émettez du composant de connexion sera prise dans votre composant de menu.

4
RemyaJ

Je suis en retard ici, mais j'essaie également de mettre à jour mon composant d'en-tête après la connexion, j'ai suivi votre approche mais il ne met pas à jour mon composant d'en-tête.

ser.service.ts

import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Subject } from 'rxjs';

@Injectable()
export class UserService {
constructor(public router: Router) {}
public getLoggedInName = new Subject(); 

async storeData(data) {
    this.getLoggedInName.next(data);
    localStorage.setItem('userData', JSON.stringify(data));
    return this.router.navigate(['']); // after login we navigate to home component, but I want to display the email in header component
}

getData() {
   return JSON.parse(localStorage.getItem('userData'));
}

logOut() {
   localStorage.setItem('userData', '');
   localStorage.clear();
   return this.router.navigate(['']);
}
}

login.component.ts

public socialSignIn(socialPlatform: string) {
      let socialPlatformProvider;
      if (socialPlatform === 'facebook') {
         socialPlatformProvider = FacebookLoginProvider.PROVIDER_ID;
      } else if (socialPlatform === 'google') {
         socialPlatformProvider = GoogleLoginProvider.PROVIDER_ID;
      }

      this.socialAuthService.signIn(socialPlatformProvider).then(userData => {
         this.apiConnection(userData);
      });
  }

  apiConnection(data){
      this.userPostData.email = data.email;
      this.userPostData.name = data.name;
      this.userPostData.provider = data.provider;
      this.userPostData.provider_id = data.id;
      this.userPostData.provider_pic = data.image;
      this.userPostData.token = data.token;
      this.user.storeData(data);

  }

socialSignIn() méthode que nous appelons cliquez sur l'icône facebook.

nav-menu.component.ts mon composant d'en-tête où je m'attends à ce que ma variable userData contienne les détails de l'utilisateur connecté.

import { Component, OnInit } from '@angular/core';
import { UserService } from '../services/user.service';

@Component({
  selector: 'app-nav-menu',
  templateUrl: './nav-menu.component.html',
  styleUrls: ['./nav-menu.component.css']
})
export class NavMenuComponent implements OnInit {
  isExpanded = false;
  isLoggedIn = false;
  public userData: any;

  constructor(public user: UserService){
    this.setUserSessionData();
  }

  ngOnInit() {
    this.user.getLoggedInName.subscribe(name => this.userData = name);
 }      

  public logOut(){
    debugger;
    this.user.logOut();
  }

  public setUserSessionData(){
    this.userData = this.user.getData();
    this.isLoggedIn = !this.userData;
  }
}

mon nav-menu.component.html où je vais montrer l'email de l'utilisateur connecté.

 <button class="nav-text" clrDropdownTrigger>
                {{userData?.email}}
                <clr-icon shape="caret down"></clr-icon>
 </button>
0
Jaydeep Shil