簡體   English   中英

在訂閱回調中更改組件的屬性后,為什么不重新渲染Angle 4 Componet的視圖?

[英]Why angular 4 componet's view doesn't rerender when component's properties are changed in subscription callbacks?

我已經使用RxJS Observer功能在angular 4中編寫了身份驗證系統。 對Oracle數據庫的查詢基於將查詢流轉換為服務中的觀察者/可觀察對象,然后在登錄組件中以登錄形式I訂閱服務中的可觀察對象以獲得身份驗證結果。 由方法返回的服務的可觀察對象,無論用戶是否通過身份驗證,都會發布“ true”或“ false”。 通過單擊登錄表單組件中的登錄按鈕,將顯示加載動畫,並且隱藏了登錄表單。 驗證用戶身份后,路由器會將用戶重定向到功能頁面。 如果用戶未通過身份驗證,則隱藏加載動畫,並再次顯示登錄表單。 但這不能按預期工作。 在控制台中,我看到用戶未登錄的輸出,並且盡管組件顯示的屬性showLoading = false和showLoginForm = true,但仍顯示加載動畫,隱藏了表單。

login.service.ts

 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(); } ); } 
我想指出的是,如果我使用Promise而不是Observer,一切都會正常。

在服

 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('Не удалось войти', 'Попробуйте ещё раз'); } ); 

請幫助我,以解決此問題並使組件重新呈現預期的效果。

嘗試更改一些內容:

  • 將組件字段注釋為正確的輸入-只需在它們前面加上@Input
  • 通過顯式指定或通過刪除關鍵字private來公開這些字段。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM