2017-10-10 43 views
0

我已經使用RxJS Observer功能在角度4中編寫了認證系統。查詢Oracle數據庫是基於查詢流在服務中轉換爲observer/observable,然後在登錄組件中使用登錄形式,我訂閱服務中的obervable以獲得身份驗證結果。服務的方法返回的可觀察對象在用戶進行身份驗證時發佈「true」或「false」。通過單擊登錄表單組件中的登錄按鈕,將顯示加載動畫並隱藏登錄表單。當用戶通過身份驗證時,路由器會將用戶重定向到功能頁面。當用戶未通過身份驗證時,加載動畫將被隱藏,並再次顯示登錄表單。但這並不如預期的那樣。在控制檯I看到輸出該用戶沒有登錄,並在加載動畫仍顯示的同時,形式是隱藏的,儘管=假和showLoginForm =真爲什麼在訂閱回調中更改組件的屬性時,角色4組件的視圖不會重新渲染?

login.service.ts組件顯示showLoading的性質

import { Injectable } from '@angular/core'; 
 
import { DbSelectService } from '../db/db-select.service'; 
 
import * as md5 from 'js-md5'; 
 
import { AuthModel, CurrentUserModel } from '../../data-models/data-models.interfaces'; 
 
import { DbSelectQueryParams } from '../../data-models/data-models.interfaces'; 
 
import { CurrentUserDbRow } from '../../data-models/db-responses.interfaces'; 
 
import { SessionService } from '../core/session.service'; 
 
import { CacheService } from '../feature/cache.service'; 
 
import { LoggerService } from '../core/logger.service'; 
 
import { Observable } from 'rxjs/Observable'; 
 
import { Observer } from 'rxjs/Observer'; 
 

 
@Injectable() 
 
export class LoginService { 
 

 
    private currentAuthData: AuthModel; 
 
    private currentUser: CurrentUserModel; 
 

 
    constructor (
 
     private dbSelect: DbSelectService, 
 
     private sessionService: SessionService, 
 
     private cacheService: CacheService, 
 
     private logger: LoggerService 
 
    ) { 
 

 
     this.currentAuthData = this.cacheService.getCurrentAuthDataCache(); 
 
     this.currentUser = this.cacheService.getCurrentUser(); 
 

 
    } 
 

 
    checkAccessRights(): Observable<boolean> { 
 

 
     return new Observable((observer: Observer<boolean>) => { 
 

 
      const queryParams: DbSelectQueryParams = { 
 
       fields: [ 
 
        `NAME`, 
 
        `ROLE` 
 
       ], 
 
       tables: [ 
 
        `SINS.P_USER` 
 
       ], 
 
       conditions: [ 
 
        `UPPER(P_USER.NAME) = UPPER(:username)`, 
 
        `AND`, 
 
        `PSWD = :password`, 
 
        `AND`, 
 
        `HASH = :hash`, 
 
        `AND`, 
 
        `LOCKED <> '1'`, 
 
        `AND`, 
 
        `ROWNUM = 1` 
 
       ] 
 
      }; 
 

 
      const bindParams = { 
 
       username: this.currentAuthData.username, 
 
       password: this.currentAuthData.password, 
 
       hash: md5(this.currentAuthData.password) 
 
      }; 
 

 
      let userIsAuthenticated = false; 
 
      const AUTHENTICATED = true; 
 
      const NOT_AUTHENTICATED = false; 
 

 
      this.dbSelect.select<CurrentUserDbRow>(queryParams, bindParams).subscribe(
 
       user => { 
 

 
        console.warn(user); 
 
        this.currentUser.username = user.NAME.toUpperCase(); 
 
        this.currentUser.role = user.ROLE.toLowerCase(); 
 

 
        this.sessionService.getAccessToUser(); 
 

 
        userIsAuthenticated = true; 
 

 
        observer.next(AUTHENTICATED); 
 
        observer.complete(); 
 

 
       }, 
 
       err => { 
 

 
        observer.error(err); 
 
        this.logger.writeError(err); 
 
        this.sessionService.closeSession(); 
 

 
       }, 
 
       () => { 
 

 
        observer.next(NOT_AUTHENTICATED); 
 
        observer.complete(); 
 

 
        if (userIsAuthenticated === NOT_AUTHENTICATED) { 
 
         this.logger.writeNewError('logon denied'); 
 
         this.sessionService.closeSession(); 
 
        } 
 

 
       } 
 
      ); 
 

 
     }); 
 

 
    } 
 

 

 
}

login.component.ts

import { Component, OnInit, OnDestroy } from '@angular/core'; 
 
import { Title } from '@angular/platform-browser'; 
 
import { AppConfig } from '../services/core/app-config.service'; 
 
import { remote } from 'electron'; 
 
import { LoginService } from '../services/auth/login.service'; 
 
import { AuthModel } from '../data-models/data-models.interfaces'; 
 
import { ToastService } from '../services/core/toast.service'; 
 
import { CacheService } from '../services/feature/cache.service'; 
 
import { AppConfigParamsModel, MaxLengthAndValueModel } from '../data-models/data-models.interfaces'; 
 
import { Subscription } from 'rxjs/Subscription'; 
 

 
@Component({ 
 
    selector: 'login', 
 
    styleUrls: ['app/login/login.component.css'], 
 
    templateUrl: 'app/login/login.component.html' 
 
}) 
 

 
export class LoginComponent implements OnInit, OnDestroy { 
 

 
    private pagename = 'Логин'; 
 
    private showLoading = false; 
 
    private showLoginForm = true; 
 
    private loginSubscription: Subscription; 
 

 
    private authmodel: AuthModel; 
 

 
    private maxlength: MaxLengthAndValueModel = { 
 
     username: 32, 
 
     password: 32 
 
    }; 
 

 
    constructor (
 
     private titleService: Title, 
 
     private config: AppConfig, 
 
     private loginService: LoginService, 
 
     private toastService: ToastService, 
 
     private cacheService: CacheService 
 
    ) { 
 

 
     this.authmodel = this.cacheService.getCurrentAuthDataCache(); 
 

 
    } 
 

 
    ngOnInit() { 
 

 
     this.config.getParams().then((params: AppConfigParamsModel) => { 
 

 
      this.titleService.setTitle(`${params.appname} - ${this.pagename}`); 
 

 
     }); 
 

 
    } 
 

 

 
    ngOnDestroy() { 
 

 
     if (this.loginSubscription) { 
 
      this.loginSubscription.unsubscribe(); 
 
     } 
 

 
    } 
 

 

 
    private onLogin(): void { 
 

 
     this.showLoadingAnimation(); 
 

 
     this.loginSubscription = this.loginService.checkAccessRights().subscribe(
 
      accessAllowed => { 
 

 
       if (accessAllowed) { 
 

 
        this.toastService.showAdviceToast('Добро пожаловать!'); 
 

 
       } else { 
 

 
        this.hideLoadingAnimation(); 
 
        this.toastService.showErrorToastWithAdvice('ВХОД ЗАПРЕЩЁН', 'Обратитесь к администратору'); 
 

 
       } 
 

 
      }, 
 
      err => { 
 

 
       this.hideLoadingAnimation(); 
 
       this.toastService.showErrorToastWithAdvice('Не удалось войти', 'Попробуйте ещё раз'); 
 

 
      } 
 
     ); 
 

 
    } 
 

 

 
    private closeWindow(): void { 
 

 
     remote.getCurrentWindow().close(); 
 

 
    } 
 

 

 
    private showLoadingAnimation(): void { 
 

 
     this.showLoading = true; 
 
     this.showLoginForm = false; 
 
     console.warn(this); 
 

 
    } 
 

 

 
    private hideLoadingAnimation(): void { 
 

 
     this.showLoading = false; 
 
     this.showLoginForm = true; 
 
     console.warn(this); 
 

 
    } 
 

 

 
}

但是,如果我改變服務方法只是爲了實驗儼然以下所示的(沒有訂閱查詢結果)組件的視圖被重新呈現良好。

checkAccessRights(): Observable<boolean> { 
 

 
     return new Observable((observer: Observer<boolean>) => { 
 

 
      const AUTHENTICATED = true; 
 
      const NOT_AUTHENTICATED = false; 
 

 
      this.currentUser.username = 'ADMIN'; 
 
      this.currentUser.role = 'admin'; 
 
      this.sessionService.getAccessToUser(); 
 
      observer.next(AUTHENTICATED); 
 
      observer.complete(); 
 

 
     }); 
 

 
    }
我要指出,這一切工作,如果我使用的承諾,而不是觀察員。

在服務

checkAccessRights(): Promise<boolean> { 
 

 
     return new Promise((resolve, reject) => { 
 

 
      const queryParams: DbSelectQueryParams = { 
 
       fields: [ 
 
        `NAME`, 
 
        `ROLE` 
 
       ], 
 
       tables: [ 
 
        `SINS.P_USER` 
 
       ], 
 
       conditions: [ 
 
        `UPPER(P_USER.NAME) = UPPER(:username)`, 
 
        `AND`, 
 
        `PSWD = :password`, 
 
        `AND`, 
 
        `HASH = :hash`, 
 
        `AND`, 
 
        `LOCKED <> '1'`, 
 
        `AND`, 
 
        `ROWNUM = 1` 
 
       ] 
 
      }; 
 

 
      const bindParams = { 
 
       username: this.currentAuthData.username, 
 
       password: this.currentAuthData.password, 
 
       hash: md5(this.currentAuthData.password) 
 
      }; 
 

 
      let userIsAuthenticated = false; 
 
      const AUTHENTICATED = true; 
 
      const NOT_AUTHENTICATED = false; 
 

 
      this.dbSelect.select<CurrentUserDbRow>(queryParams, bindParams).subscribe(
 
       user => { 
 

 
        console.warn(user); 
 
        this.currentUser.username = user.NAME.toUpperCase(); 
 
        this.currentUser.role = user.ROLE.toLowerCase(); 
 

 
        this.sessionService.getAccessToUser(); 
 

 
        userIsAuthenticated = true; 
 

 
        resolve(AUTHENTICATED); 
 

 
       }, 
 
       err => { 
 

 
        reject(err); 
 
        this.logger.writeError(err); 
 

 
       }, 
 
       () => { 
 

 
        resolve(NOT_AUTHENTICATED); 
 

 
        if (userIsAuthenticated === NOT_AUTHENTICATED) { 
 
         this.logger.writeNewError('logon denied'); 
 
        } 
 

 
       } 
 
      ); 
 

 
     }); 
 

 
    }

在組分

this.loginService.checkAccessRights().then(
 
      accessAllowed => { 
 

 
       if (accessAllowed) { 
 

 
        this.toastService.showAdviceToast('Добро пожаловать!'); 
 

 
       } else { 
 

 
        this.hideLoadingAnimation(); 
 
        this.toastService.showErrorToastWithAdvice('ВХОД ЗАПРЕЩЁН', 'Обратитесь к администратору'); 
 

 
       } 
 

 
      } 
 
     ).catch(
 
      err => { 
 

 
       this.hideLoadingAnimation(); 
 
       this.toastService.showErrorToastWithAdvice('Не удалось войти', 'Попробуйте ещё раз'); 
 

 
      } 
 
     );

請幫助我解決此問題並按預期進行組件重新渲染。

+0

有時,問題來自於退訂方法。 – Wandrille

+0

在此代碼的以前版本中,取消訂閱方法不存在,並且問題相同 –

回答

0

試圖去改變一些事情:

  • 註釋你的組件領域正確的輸入 - 只是@Input前面加上他們;
  • 通過明確指定或僅刪除關鍵字private來公開這些字段。

@Input() showLoading = false; 
    @Input() showLoginForm = true; 
+0

這也未解決問題。我想說明的是,如果我使用Promise而不是Observer,那麼一切正常。 –

相關問題