2017-09-28 7 views
0

ログインしているかどうかを教えてくれるAuthServiceのプロパティがあります。ngIfは非同期コードを評価しませんAngular and Firebase

私が正しくログインすると、ログアウトをクリックしたときにisLogInをtrueに設定し、プロパティをfalseに設定しました。私はAppComponent(最初のコンポーネントがロードされている)にこのロジックを持っています。

私が持っている私のHeaderComponentで
firebase.auth().onAuthStateChanged((user) => { 
     if (user) { 
     // User is signed in. 
     this.authService.user = new User(user.displayName, user.email, user.photoURL, user.uid); 

     console.log(user); 
     this.isLoading = false; 
     this.authService.isLogIn.next(true); 
     } else { 
     // No user is signed in. 
     console.error('no user is login'); 
     this.authService.isLogIn.next(false); 
     } 
    }); 

export class HeaderComponent implements OnInit { 
    isActivated = false; 
    constructor(private authService: AuthService) { } 
    ngOnInit() { 
    this.authService.isLogIn.asObservable().subscribe(
     (data: boolean) => { 
     this.isActivated = data; 
     } 
    ); 
    // this.isActivated = this.authService.isLogin(); 
    } 

} 

テンプレート:私はここにapprochingてる何

<ng-template [ngIf]="!isActivated"> 
     <a class="nav-item nav-link text-white anchor-hover" 

     routerLink="/login" 
     routerLinkActive="active font-weight-bold"> 
     <i class="fa fa-sign-in pr-2" aria-hidden="true"></i>Ingresar 
     </a> 
    </ng-template> 
    <ng-template [ngIf]="isActivated"> 
     <!--DROPDOWN PROFILE--> 
     <div class="btn-group" role="group" *ngIf="authService.user"> 
     <button id="btnGroupDrop1" type="button" class="btn btn-light dropdown-toggle pointer" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> 
      {{authService.user.displayName}} 
     </button> 
     <div class="dropdown-menu dropdown-menu-right" aria-labelledby="btnGroupDrop1"> 
      <a class="dropdown-item" href="#">Dropdown link</a> 
      <a class="dropdown-item" href="#">Dropdown link</a> 
     </div> 
     </div> 
     <a class="nav-item nav-link text-white anchor-hover" 
     routerLink="/dashboard" 
     routerLinkActive="active font-weight-bold"> 
     <i class="fa fa-sign-in pr-2" aria-hidden="true"></i>Dashboard 
     </a> 
    </ng-template> 

は、ユーザーがログインするときに、私は彼にダッシュボードのボタンを示すことがありますログインボタンを非表示にしますが、これはページを更新したり現在のルートを変更した場合にのみ表示されます。あなたがログインしているかどうかに応じて、ルートを変更したり、ページを更新して異なるUIコンポーネントを表示する必要はありません。

は今、私はあなたの全体のファイルを聞かせて: AppRoutingモジュール:

import { NgModule } from '@angular/core'; 
import { Routes, RouterModule } from '@angular/router'; 
import {HomeComponent} from './shared/home/home.component'; 
import {LoginComponent} from './public/login/login.component'; 
import {DashboardComponent} from './auth/dashboard/dashboard.component'; 

const routes: Routes = [ 
    {path: '', component: HomeComponent}, 
    {path: 'login', component: LoginComponent}, 
    {path: 'dashboard', component: DashboardComponent} 
]; 
@NgModule({ 
    imports: [RouterModule.forRoot(routes)], 
    exports: [RouterModule] 
}) 
export class AppRoutingModule{} 

AppComponent.ts

import {Component, OnInit} from '@angular/core'; 
import * as firebase from 'firebase'; 
import {AuthService} from './public/services/auth.service'; 
import {User} from "./auth/models/user.model"; 

@Component({ 
    selector: 'app-root', 
    templateUrl: './app.component.html', 
    styleUrls: ['./app.component.css'] 
}) 
export class AppComponent implements OnInit { 
    isLoading = true; 
    constructor(private authService: AuthService) {} 

    ngOnInit() { 

    // this.authService.isLogIn.next(localStorage.length > 0); 

    firebase.auth().onIdTokenChanged(
     (data) => { 
     console.log('TOKEN HAS CHANGED', data); 
     if(data) { 
      data.getIdToken().then(
      (tk) => { 
       this.authService.token = tk; 
      } 
     ); 
     } else { 
      console.log('You don\'t have a token yet, please login...'); 
      // TODO this means that the user is new or have logout. 
     } 
     } 
    ); 

    firebase.auth().onAuthStateChanged((user) => { 
     if (user) { 
     // User is signed in. 
     this.authService.user = new User(user.displayName, user.email, user.photoURL, user.uid); 

     console.log(user); 
     this.isLoading = false; 
     this.authService.isLogIn.next(true); 
     } else { 
     // No user is signed in. 
     console.error('no user is login'); 
     this.authService.isLogIn.next(false); 
     } 
    }); 

    // check localstorage, so we can see if there is a logged user 
    if (this.authService.getLocalUserInfo()) { 
     this.authService.isLogIn.next(true); 
    } else { 
     this.authService.isLogIn.next(false); 
    } 
    } 
} 

AppComponentテンプレート:

<div> 
    <app-header></app-header> 
</div> 


<div> 
    <router-outlet></router-outlet> 
</div> 

AppHeader.ts

import { Component, OnInit } from '@angular/core'; 
import {AuthService} from '../../public/services/auth.service'; 

@Component({ 
    selector: 'app-header', 
    templateUrl: './header.component.html', 
    styleUrls: ['./header.component.css'] 
}) 
export class HeaderComponent implements OnInit { 
    isActivated = false; 
    constructor(private authService: AuthService) { } 
    ngOnInit() { 
    this.authService.isLogIn.asObservable().subscribe(
     (data: boolean) => { 
     this.isActivated = data; 
     } 
    ); 
    // this.isActivated = this.authService.isLogin(); 
    } 

} 

AppHeaderテンプレート

<nav class="navbar navbar-expand-lg navbar-dark bg-custom-nav px-5"> 
    <a class="navbar-brand" routerLink="/">MovieApp</a> 
    <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation"> 
    <span class="navbar-toggler-icon"></span> 
    </button> 
    <div class="container-fluid"> 
    <div class="collapse navbar-collapse d-lg-flex justify-content-lg-between row" id="navbarNavAltMarkup"> 
     <div class="navbar-nav px-sm-4 px-lg-0"> 
     <a class="nav-item nav-link text-white" 
      routerLink="/" 
      routerLinkActive="active font-weight-bold" 
      [routerLinkActiveOptions]="{exact: true}">Inicio</a> 
     </div> 
     <div class="col-lg-8"> 
     <app-search-bar></app-search-bar> 
     </div> 
     <div class="row"> 
     <ng-template [ngIf]="!isActivated"> 
      <a class="nav-item nav-link text-white anchor-hover" 

      routerLink="/login" 
      routerLinkActive="active font-weight-bold"> 
      <i class="fa fa-sign-in pr-2" aria-hidden="true"></i>Ingresar 
      </a> 
     </ng-template> 
     <ng-template [ngIf]="isActivated"> 
      <!--DROPDOWN PROFILE--> 
      <div class="btn-group" role="group" *ngIf="authService.user"> 
      <button id="btnGroupDrop1" type="button" class="btn btn-light dropdown-toggle pointer" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> 
       {{authService.user.displayName}} 
      </button> 
      <div class="dropdown-menu dropdown-menu-right" aria-labelledby="btnGroupDrop1"> 
       <a class="dropdown-item" href="#">Dropdown link</a> 
       <a class="dropdown-item" href="#">Dropdown link</a> 
      </div> 
      </div> 
      <a class="nav-item nav-link text-white anchor-hover" 
      routerLink="/dashboard" 
      routerLinkActive="active font-weight-bold"> 
      <i class="fa fa-sign-in pr-2" aria-hidden="true"></i>Dashboard 
      </a> 
     </ng-template> 

     </div> 
    </div> 
    </div> 
</nav> 

AuthService.ts

import * as firebase from 'firebase'; 
import {Router} from '@angular/router'; 
import { Injectable } from "@angular/core"; 
import {Subject} from "rxjs/Subject"; 
import {User} from "../../auth/models/user.model"; 

@Injectable() 
export class AuthService { 
    token: string; 
    isLogIn = new Subject<boolean>(); 
    user: User; 


    constructor(private router: Router){} 

    signinWithFacebook() { 
    const provider = new firebase.auth.FacebookAuthProvider(); 
    provider.addScope('user_location'); 
    return firebase.auth().signInWithPopup(provider) 
     .then(
     (res) => { 
      console.log(res); 
      this.getTokenId(); 
      localStorage.setItem('userInfo', JSON.stringify(firebase.auth().currentUser.providerData[0])); 
      const userInfo = firebase.auth().currentUser.providerData[0]; 
      this.user = new User(userInfo.displayName, userInfo.email, userInfo.photoURL, userInfo.uid); 

      this.isLogIn.next(true); 
      this.router.navigate(['/dashboard']); 
     } 
    ); 
    } 

    getTokenId() { 
    firebase.auth().currentUser.getIdToken() 
     .then(
     (tk) => { 
      return this.token = tk; 
     } 
    ); 
    } 

    logout() { 
    return firebase.auth().signOut(); 
    // handle in component 
    } 

    getLocalUserInfo(): boolean { 
    if(localStorage.getItem('userInfo')) { 
     const transformStoredUser = JSON.parse(localStorage.getItem('userInfo')); 
     this.user = new User(transformStoredUser.displayName, transformStoredUser.email, transformStoredUser.photoURL, transformStoredUser.uid); 
     return true; 
    } else { 
     return false; 
    } 
    } 
    isLogin():boolean { 
    if (localStorage.getItem('userInfo')) { 
     return true; 
    } 
    return false; 
    } 
} 

あなたは、完全なプロジェクトを見つけることができます:​​3210もう一つ、私は非同期パイプを使用しましたが、テンプレートにはありません chagesを反映します。 githubプロジェクトでは、テンプレートで非同期を使用していますが、同じバグが残っています。誰かが私を助けてくれることを願っている

答えて

1

私は助けてくれるようにしようとしていますが、あなたには目を見張るようなコードがたくさんありますので、何かが分からないことがあります。とにかく、うまくいけばあなたのコードを整理し、あなたが正しい方向を指すように、AsyncPipeを調べることができます。

最初にisLogIn = new Subject<boolean>();private _isLogIn = new Subject<boolean>();に変更して、AuthServiceを改良してインライン化したいと考えています。私たちはSubjectをそれを変更する他のコンポーネントに共有したくないので、AuthServiceのどこでもアンダースコアを追加するだけです...最後にSubjectをエクスポートして、このようなget関数を追加することができます:

get isLogIn(): Observable<boolean> { 
    return this._isLogIn.asObservable(); 
} 

そして今、我々はチェーンにasObservable()ところ、我々はそれを使用し、これまでには必要ありません。

また、ユーザーの状態の変化をAppComponentからAuthServiceに移動する必要があります。次に、AppModuleのコンストラクタでサービスをインスタンス化して、アプリケーションが起動するとすぐにサービスがauth状態の変更を監視し始めます。

また、認証状態の解決がゾーン外になる可能性があるため、この場合は必ずコアからNgZoneをインポートしてAuthServiceのコンストラクタconstructor(private router: Router, private _zone: NgZone) { }に渡す必要がありますあなたが認証状態の値を更新するときに、あなたは、この関数でラップすることができます

export class HeaderComponent implements OnInit { 
    constructor(private authService: AuthService) { } 

    ngOnInit() {} 

    get isActivated(): Observable<boolean> { 
    return this.authService.isLogIn; 
    } 
} 

そこで彼:私はあなたのheader.component.tsを書くことだった場合

this._zone.run(() => { 
    // your code here 
} 

は今、私はこのような何かをやっているだろう私はちょうどget関数を使って観測可能なテンプレートをテンプレートに渡しています。だから、テンプレートで、私はそうのようなAsyncPipeを実装します:

<div *ngIf="!(isActivated | async) else user"> 
    <a class="nav-item nav-link text-white anchor-hover" routerLink="/login" 
    routerLinkActive="active font-weight-bold"> 
    <i class="fa fa-sign-in pr-2" aria-hidden="true"></i>Ingresar 
    </a> 
</div> 
<ng-template #user> 
    <!--DROPDOWN PROFILE--> 
    <div class="btn-group" role="group" *ngIf="authService.user"> 
    <button id="btnGroupDrop1" type="button" class="btn btn-light dropdown-toggle pointer" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true"> 
     {{authService.user.displayName}} 
    </button> 
    <div class="dropdown-menu dropdown-menu-right" aria-labelledby="btnGroupDrop1"> 
     <a class="dropdown-item" href="#">Dropdown link</a> 
     <a class="dropdown-item" href="#">Dropdown link</a> 
    </div> 
    </div> 
    <a class="nav-item nav-link text-white anchor-hover" 
    routerLink="/dashboard" 
    routerLinkActive="active font-weight-bold"> 
    <i class="fa fa-sign-in pr-2" aria-hidden="true"></i>Dashboard 
    </a> 
</ng-template> 

AsyncPipeは自動的にサブスクライブして、観察可能に退会とリフレッシュ/ゾーンの更新を処理します。

ここで、コードが期待どおりに動作するようにするためのいくつかの概要/基本的な変更を行いました。私はあなたにこれを試して、あなたの*ngIfがもっと "うまく"働くかどうかを見てみましょう。しかし、あなたがAngularで他のものを調べたいかもしれません... =>https://stackoverflow.com/a/43006589/5076023

+0

また、あなたのAuthServiceで 'firebase.auth()。onAuthStateChanged'を処理して、あなたのAppModuleのコンストラクタでサービスをインスタンス化することができます。私はあなたがAuthServiceでこれをしていないことを忘れました – MichaelSolati

+0

私はあなたの手順に従ってきましたが、どうすればisLogInに値を設定できますか?セットで? –

+0

あなたが私のコメントを見たかどうか分かりませんが、authserviceのユーザー状態を見ていないことを忘れていましたので、そこで移動することをお勧めします。 (上記のコメントを参照) – MichaelSolati

関連する問題