我已經使用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('Не удалось войти', 'Попробуйте ещё раз');
}
);
請幫助我解決此問題並按預期進行組件重新渲染。
有時,問題來自於退訂方法。 – Wandrille
在此代碼的以前版本中,取消訂閱方法不存在,並且問題相同 –