我现在只在Angular工作了几个月,目前对这些服务不知所措。我正在使用3个相互交互的角度服务。 authService,configService和guardService。
在我的guardService中, checkBusinessCase(bcase)方法检查当前业务案例,并在AuthService中使用方法 this.authService.setActiveBusinessCase(bcase)进行设置。
guardService看起来像这样:
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
import { Observable, of } from 'rxjs';
import { UserAuthService } from './user-auth.service';
import { Constants } from '../../constants';
import { catchError, map } from 'rxjs/operators';
@Injectable()
export class BcaseRequiredGuard implements CanActivate {
constructor(private router: Router,
private authService: UserAuthService) {
}
canActivate(next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
if (next.data['bcase']) {
return this.checkBusinessCase(next.data['bcase']);
}
if (next.data['bcaseRegExp']) {
return this.checkBusinessCase(new RegExp(next.data['bcaseRegExp']));
}
this.router.navigate([Constants.routing.error, 'invalidBusinessCase']);
return false;
}
checkBusinessCase(bcase): Observable<boolean> {
return this.authService.isLoggedIn().pipe(
map(isLoggedIn => {
const accept = isLoggedIn && this.authService.hasBusinessCase(bcase);
if (accept) {
console.log('This guard approved that the Business case ' + bcase + ' is assigned to ' + this.authService.user.user_name);
this.authService.setActiveBusinessCase(bcase);
} else {
console.log('This guard approved that the Business case ' + bcase + ' is not assigned to ' + this.authService.user.user_name);
this.router.navigate([Constants.routing.home]);
}
return accept;
}),
catchError((err) => {
console.error(Constants.errors.loginCheckFailed, err);
this.router.navigate([Constants.routing.error, 'loginCheckFailed']);
return of(false);
}));
}
}
正是这个业务案例,现在我需要在configService中的 getAutoConfiguredBCLanguage()方法中。当我尝试使用 this.authService.activeBusinessCase 访问它时,由于configService在authService之前被调用,因此我未定义。
configService如下所示:
import { Injectable } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import 'moment/locale/de';
import { UserAuthService } from 'app/auth/user-auth.service';
@Injectable()
export class ConfigurationService {
defaultLanguage = 'en';
activeBusinessCase = '';
languages = {
en: 'English',
de: 'German',
es: 'Spanish',
ja: 'Japanese',
pt: 'Portuguese'
};
// Business cases with available translation files
businessCases = {
case1: '_case1',
case2: '_case2',
case3: '_case3'
};
constructor(
private translate: TranslateService,
private authService: UserAuthService
) {
}
// Get business case specific language
// TODO: Get currently logged in business case
getAutoConfiguredBCLanguage(){
const browserLang = this.translate.getBrowserLang();
console.log('BROWSER LANGUAGE: ', browserLang);
console.log('ACTIVE BUSINESS CASE: ', this.activeBusinessCase);
if (this.languages.hasOwnProperty(browserLang) && this.activeBusinessCase !== undefined) {
switch (this.activeBusinessCase) {
case 'CASE1':
return browserLang.concat(this.businessCases.case1);
case 'CASE2':
return browserLang.concat(this.businessCases.case2);
case 'CASE3':
return browserLang.concat(this.businessCases.case2);
default:
return browserLang;
}
} else if (this.languages.hasOwnProperty(browserLang) && this.activeBusinessCase === undefined) {
console.log('No currently active business case.');
return browserLang;
} else {
return this.defaultLanguage;
}
}
}
这是authService,其中设置了我需要其值的activeBusinessCase属性:
import { Injectable } from '@angular/core';
import { Router } from '@angular/router';
import { Constants } from '../../constants';
import { EMPTY, Observable } from 'rxjs';
import { PathLocationStrategy } from '@angular/common';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { translate } from '../shared/translation-util';
import { environment } from '../../environments/environment';
import { LoginError } from '../model/auth/LoginError';
import { User } from '../model/auth/User';
import { UiInfo } from '../model/auth/UiInfo';
import { ChangePasswordError } from '../model/auth/ChangePasswordError';
import { Title } from '@angular/platform-browser';
import { catchError, map, mergeMap, publishReplay, refCount, tap } from 'rxjs/operators';
import { LoginResponse } from '../model/auth/LoginResponse';
@Injectable()
export class UserAuthService {
activeBusinessCase: string;
constructor(private router: Router,
private httpClient: HttpClient,
private pls: PathLocationStrategy,
private titleService: Title) {
}
setActiveBusinessCase(bcase: string) {
this.activeBusinessCase = bcase;
this.setTitle(bcase);
}
}
如何在configService中获得当前业务案例(activeBusinessCase)?
更新:
在采用 fridoo 的更改并根据我的需要进行调整之后,现在一切看起来都更加合乎逻辑。但是现在我在其他地方遇到了我无法处理的错误消息。这是控制台中的虚线和错误消息。
在我的http.service.ts中:
getResource(key: string, lang: string): Observable<any> {
const headers = new HttpHeaders({'Accept': 'text/html'});
return this.httpClient.get('/resources/' + key,
{
headers: headers,
responseType: 'text',
params: new HttpParams()
.set('businessCase', this.authService.activeBusinessCase ? this.authService.activeBusinessCase :
environment.default_business_case)
.set('lang', lang)
}).pipe(
catchError(() => {
return this.translateService.get('Not-available').pipe(
map(res => '<h4 style="text-align: center">' + res + '</h4>'));
})
);
}
错误消息:
“ activeBusinessCase”属性是私有的,只能在“ UserAuthService”类中访问。
我的user-auth.service.ts
login(name: string, password: string, imTid: string): Observable<UiInfo> {
return this.loginWithBackend(name, password, imTid).pipe(
tap(() => {
this.user.user_name = translate('default-user');
// TODO: Check if loggedoff is obsolete?
if (this.loggedOff) {
this.pls.back();
} else if (this.redirectUrl) {
this.router.navigate([this.redirectUrl]);
this.redirectUrl = null;
console.log(Constants.texts.loginSuccessRedirect);
} else {
console.log('Active Business Case', this.activeBusinessCase);
if (this.activeBusinessCase) {
this.router.navigate([Constants.routing.explorer + this.activeBusinessCase.toLowerCase()]);
} else {
const err = new LoginError('Business case is missing');
throw err;
}
}
this.loggedOff = false;
}));
错误消息:
类型“ BehaviorSubject”上不存在属性“ toLowerCase”。
我的home.component.ts
export class HomeComponent implements OnInit {
routing = Constants.routing;
constructor(private router: Router,
private authService: UserAuthService) {
}
ngOnInit() {
this.router.navigate([Constants.routing.explorer + this.authService.activeBusinessCase.toLowerCase()]);
}
}
错误消息:
“ activeBusinessCase”属性是私有的,只能在“ UserAuthService”类中访问。
答案 0 :(得分:1)
由于activeBusinessCase
是异步设置的,因此您希望在应用的另一部分收到有关值更改的通知时,它应该是Subject
。使用BehaviorSubject
,以便在订阅后立即获得当前值。
// ----- UserAuthService -----
public activeBusinessCase$ = new BehaviorSubject<string>(null);
setActiveBusinessCase(bcase: string) {
this.activeBusinessCase.next(bcase);
this.setTitle(bcase);
}
在ConfigurationService中收听activeBusinessCase$
的值更改,并将传入的值映射到要返回的语言。
// ----- ConfigurationService -----
// will emit a new language every time activeBusinessCase changes,
// this behavior could be changed depending on your specific needs
getAutoConfiguredBCLanguage$(): Observable<string> {
return this.authService.activeBusinessCase$
.pipe(
// use 'distinctUntilChanged' to only emit values that are different from the previous,
distinctUntilChanged(),
map(abc => this.getAutoConfiguredBCLanguage(abc))
);
}
private getAutoConfiguredBCLanguage(activeBusinessCase: string): string {
// no changes here apart from the input parameter - I omitted the code for brevity
// use the parameter activeBusinessCase instead of this.activeBusinessCase here
}
在需要使用该语言的地方订阅getAutoConfiguredBCLanguage$
。
// ----- AppComponent -----
initLanguage() {
this.configService.getAutoConfiguredBCLanguage$()
.pipe(takeUntil(this.destroy$)) // unsubscribe when the component gets destroyed
.subscribe(lang => {
// use the language here
});
}
private destroy$ = new Subject<void>();
onDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
BehaviorSubject
具有函数getValue
,该函数返回BehaviorSubject
发出的最后一个值。您可以使用此函数来获取当前的activeBusinessCase
,但只有在知道自己在做什么的情况下才能这样做,即,如果您确实想在特定时间获取当前值,请致电{ {1}}。请记住,您正在处理应用程序中的异步操作。如果要确保通过调用getValue
设置了activeBusinessCase$
的值,则必须订阅this.authService.setActiveBusinessCase
。如果您不在乎是否已设置BehaviorSubject
,而只想使用activeBusinessCase$
的当前值,则可以使用activeBusinessCase$
(然后可能会返回已设置的getValue
作为null
的初始值。
我的建议:
activeBusinessCase$