web-dev-qa-db-ja.com

Angular2でのログイン後のヘッダーの更新

そのため、ユーザーがログインしているかどうかに応じて、ユーザー名または「サインイン」のいずれかを表示するヘッダーコンポーネントがあります。また、ログインのすべてのビジネスロジックを実行するLoginコンポーネントもあります。現在、親/子関係はありません。

ユーザーがログインすると、ブラウザーでページ全体の更新が行われない限り、ヘッダーは更新または変更されません。これを行うさまざまな方法について、オンラインで多くの検索と読み取りを行ってきました。 ngOnChanges、NgZone、ApplicationRef、およびChangeDetectorRefが最も人気があるようです。これはChangeDetectorRefでこの動作を実装しようとしています。これは私の状況に最も関連があるようです。ただし、これを使用する方法の実際の例を見つけることはできません。

コーディングしましたが、何もしないようです。アドバイスをいただければ幸いです。私は間違ったアプローチをとっていて、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

そのため、私は自分のサービスを使用して変更を発行するというアドバイスをいくつか受けました。 Stack Overflowのいくつかの場所で、この方法でサービスを使用するのは悪いパターンであり、送信は子コンポーネントから親コンポーネントにのみ発生するはずだと読みました。したがって、これが「適切な」方法であるかどうかはわかりませんが、複数のコンポーネントにこのイベントを知らせたいので、私にとってはうまくいきます。

私はすでに自分の認証を扱っているサービスを持っているので、私がしなければならなかったのは、それをエミッターに与え、適切なタイミングで放出し、それから私のコンポーネントで放出を聞くことでした。

ヘッダーコンポーネント

export class HeaderComponent {
    userName: string;

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

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

認証サービス

@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は良かった。しかし、これはもっと簡単です。これは、データを発行およびサブスクライブする代替方法です。

ヘッダーコンポーネント

export class HeaderComponent implements OnInit {
    userName: string;

    constructor(private authenticationService: AuthenticationService) {}

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

}

認証サービス

@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');
    }
}

Subject() を試してください。ハッピーコーディング。

7

これを行うことができます->

ヘッダーコンポーネント->

 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();
    }

ログインサービス->

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

ログインコンポーネントから出力している値は、メニューコンポーネントで捕捉されます。

4
RemyaJ

私はここに遅れていますが、ログイン後にヘッダーコンポーネントを更新しようとしています。あなたのアプローチに従いましたが、ヘッダーコンポーネントを更新していません。

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);

  }
_

Facebookアイコンをクリックすると呼び出されるsocialSignIn()メソッド。

nav-menu.component.tsuserData変数にログインしているユーザーの詳細があると予想されるヘッダーコンポーネント。

_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;
  }
}
_

my nav-menu.component.htmlログインしたユーザーのメールを表示します。

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