我有一个使用ngrx-store的Angular应用程序。我的功能部件有以下文件
<componentname>.actions.ts
<componentname>.effects.ts
<componentname>.model.ts
<componentname>.module.ts
<componentname>.reducer.ts
<componentname>.state.ts
<componentname>.selectors.ts
<componentname>-routing.module.ts
我对Observables和NGRX存储都是陌生的,我需要一些帮助来从存储中检索值(emailAddress),然后在服务API调用中使用它。在服务方法中,我可以订阅并控制台记录该值,但是在进行服务调用时,该值为空白,因此我不会取回数据。
我如何订阅emailAddress选择器并同时调用服务API以确保该值在那里。用户登录时,商店中的电子邮件地址仅存储一次,该值永不变。
我的组件
import { selectStrava } from "@app/strava/strava.selector";
import { selectEmailAddress } from "@app/core/auth/auth.selectors";
@Component({
selector: "srm-strava",
templateUrl: "./strava.component.html",
styleUrls: ["./strava.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class StravaComponent implements OnInit {
@Input()
strava$: Observable<Strava>;
constructor(private stravaStore: Store<IStravaState>) {
this.strava$ = this.stravaStore.pipe(select(selectStrava));
}
ngOnInit() {
this.stravaStore.dispatch(new GetStravaAuthorization());
}
}
我的组件选择器
import { createFeatureSelector, createSelector } from '@ngrx/store';
import * as fromAppStore from "@app/core/auth/auth.reducer";
import { IStravaState } from './strava.state';
export const selectStravaState = createFeatureSelector<IStravaState>('strava');
export const state = createSelector(selectStravaState, (stravaState: IStravaState) => stravaState);
export const selectStrava = createSelector(state, (stravaState: IStravaState) => stravaState.strava);
我在API服务中的方法
constructor(http: HttpClient, notificationService: NotificationService, appState: Store<AppState>) {
this.http = http;
this.notificationService = notificationService;
this.appState = appState;
}
public getStravaAuthorization(): Observable<Strava> {
this.emailAddress$ = this.appState.pipe(select(selectEmailAddress));
//the following outputs to the console OK
this.emailAddress$.subscribe(res => { console.log(res) });
//the email address is blank on the next call
let getStravaApi = `${AppSettings.CONTACTS_API_HOST}employee/strava?emailaddress=${this.emailAddress$}`;
return this.http.get<Strava>(getStravaApi).pipe(
tap(result => console.log('getStravaAccess: executed with email ')),
map(result => result));
};
我的效果如下
@Effect()
getStravaAuthorization$ = this.actions$.pipe(
ofType<GetStravaAuthorization>(StravaActionTypes.GetStravaAuthorization), mergeMap(() => this.stravaService.getStravaAuthorization()
.pipe(map((strava: Strava) => new GetStravaAuthorizationSuccess(strava))))
);
从商店中检索值的电子邮件地址选择器是
export const selectEmailAddress = createSelector(
selectAuth, (state: AuthState) => {
if ((state.userDetails === null || state.userDetails === undefined))
return "";
else
return state.userDetails.email
;
}
);
我的控制台日志如下
根据建议,将代码从服务移至组件,我现在在this.emailAddress $上收到一条错误消息,指出“无法为'new'表达式类型不匹配选择重载。参数emailAddress应该具有可分配给字符串的类型,但是具有类型可观察的
更新的组件代码
import { Component, ChangeDetectionStrategy, OnInit, Input } from "@angular/core";
import { Observable } from "rxjs";
import { take } from "rxjs/operators";
import { Store, select } from "@ngrx/store";
import { GetStravaAuthorization } from "@app/strava/strava.actions";
import { Strava } from "@app/strava/strava.model";
import { IStravaState } from "@app/strava/strava.state"
import { AuthState } from "@app/core/auth/auth.model.ts";
import { AppState } from "@app/core/core.state.ts"
import { selectStrava } from "@app/strava/strava.selector";
import { selectEmailAddress } from "@app/core/auth/auth.selectors";
@Component({
selector: "srm-strava",
templateUrl: "./strava.component.html",
styleUrls: ["./strava.component.scss"],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class StravaComponent implements OnInit {
@Input()
strava$: Observable<Strava>;
@Input()
emailAddress$: Observable<string>;
constructor(private stravaStore: Store<IStravaState>, private appState: Store<AppState>) {
this.strava$ = this.stravaStore.pipe(select(selectStrava));
}
ngOnInit() {
this.emailAddress$ = this.appState.pipe(select(selectEmailAddress));
this.stravaStore.dispatch(new GetStravaAuthorization(this.emailAddress$));
}
}
更新代码
我的组件
ngOnInit() {
this.appState
.pipe(
select(selectEmailAddress),
first()
)
.subscribe((emailAddress) => {
this.stravaStore.dispatch(new GetStravaAuthorization(emailAddress)); //dispatch action with the payload containing email address
});
}
我的效果
@Effect()
getStravaAuthorization$ = this.actions$
.pipe(
ofType<GetStravaAuthorization>(StravaActionTypes.GetStravaAuthorization),
mergeMap((action) => {
// passing the action's payload (email address) below to service
return this.stravaService.getStravaAuthorization(action.payload);
},
map((strava: Strava) => new GetStravaAuthorizationSuccess(strava)))
);
我的服务
public getStravaAuthorization(emailAddress): Observable<Strava> {
let getStravaApi = `${AppSettings.CONTACTS_API_HOST}employee/strava?emailaddress=${emailAddress}`;
return this.http.get<Strava>(getStravaApi).pipe(
tap(result => console.log('getStravaAccess: executed with emaiL address ')),
map(result => result));
}
动作
export class GetStravaAuthorization implements Action {
readonly type = StravaActionTypes.GetStravaAuthorization;
constructor(public payload: string) { }
}
export class GetStravaAuthorizationSuccess implements Action {
readonly type = StravaActionTypes.GetStravaAuthorizationSuccess;
constructor(public payload: Strava) { }
}
还有其他要指出的是EmailAddress不是IStraviaState的一部分
import { Strava } from "@app/strava/strava.model";
export interface IStravaState {
strava: Strava;
}
export const initialStravaState: IStravaState = {
strava: null
};
export class Strava {
stravaAuthorization: StravaAuthorization
}
export class StravaAuthorization {
entityId: string;
accessToken: string;
refreshToken: string;
isAuthorized: boolean;
}
我现在看到的是更新后的错误
答案 0 :(得分:0)
在下面的行中,假设this.emailAddress$
是电子邮件地址的值,而您传递的是Observable
。这就是为什么它不起作用的原因。
let getStravaApi = `${AppSettings.CONTACTS_API_HOST}employee/strava?emailaddress=${this.emailAddress$}`;
我强烈建议您通过组件中的电子邮件 ,因为该服务在大多数情况下都不应该访问商店。 如果您仍想订阅服务中的状态,则可以执行以下操作:
public getStravaAuthorization(): Observable<Strava> {
return this.appState.pipe(
select(selectEmailAddress),
first(), // the subscription is immediately ended after retrieval
mergeMap((emailAddress) => { // getting email address and chaining observables
let getStravaApi = `${AppSettings.CONTACTS_API_HOST}employee/strava?emailaddress=${emailAddress}`;
return this.http.get<Strava>(getStravaApi);
}),
tap(result => console.log('getStravaAccess: executed with email ')),
map(result => result)); // you actually don't need this if you're not modifying result
);
};
请确保您的操作支持名为payload
的参数。
即像这样:
export class MyAction {
readonly type = MY_TYPE;
constructor(public payload: string) {}
}
组件:
export class StravaComponent implements OnInit {
@Input()
strava$: Observable<Strava>;
@Input()
emailAddress$: Observable<string>;
constructor(private stravaStore: Store<IStravaState>, private appState: Store<AppState>) {
this.strava$ = this.stravaStore.pipe(select(selectStrava));
}
ngOnInit() {
this.appState
.pipe(
select(selectEmailAddress),
first()
)
.subscribe((emailAddress) => {
this.stravaStore.dispatch(new GetStravaAuthorization(emailAddress)); //dispatch action with the payload containing email address
});
}
}
效果:
@Effect()
getStravaAuthorization$ = this.actions$
.pipe(
ofType<GetStravaAuthorization>(StravaActionTypes.GetStravaAuthorization),
mergeMap((action) => {
// passing the action's payload (email address) below to service
return this.stravaService.getStravaAuthorization(action.payload);
},
map((strava: Strava) => new GetStravaAuthorizationSuccess(strava)))
);
服务:
public getStravaAuthorization(emailAddress): Observable<Strava> {
// assigning the emailAdress to the url's param
let getStravaApi = `${AppSettings.CONTACTS_API_HOST}employee/strava?emailaddress=${emailAddress}`;
return this.http.get<Strava>(getStravaApi).pipe(
tap(result => console.log('getStravaAccess: executed with email ')),
map(result => result));
};
答案 1 :(得分:0)
您似乎在构建请求时尝试将Observable用作字符串值。
let getStravaApi = `${AppSettings.CONTACTS_API_HOST}employee/strava?emailaddress=${this.emailAddress$}`;`
有几种方法可以实现这一点,我将分享异步/等待路由。
您可以使用.toPromise()
方法将可观察结果转换为Promise,以等待结果。
public async getStravaAuthorization(): Observable<Strava> {
...
const emailAddress = await this.emailAddress$.toPromise();
...
}
答案 2 :(得分:0)
您应该从getStravaAuthorization效果中选择电子邮件地址。因此,您可以从组件中分派新的GetStravaAuthorization()而不发送电子邮件,但是效果会在未定义null时从选择器中获取电子邮件,并将其传递给我们的服务。
@Effect()
getStravaAuthorization$ = this.actions$.pipe(
ofType<GetStravaAuthorization>(StravaActionTypes.GetStravaAuthorization),
switchMap(() => this.store.pipe(select(selectEmailAddress))),
filter(Boolean),
mergeMap((email: string) => this.stravaService.getStravaAuthorization(email)
.pipe(map((strava: Strava) => new GetStravaAuthorizationSuccess(strava))))
);
答案 3 :(得分:-1)
我能够通过如下更新组件来解决
ngOnInit() {
this.emailAddress$ = this.authStore.pipe(select(selectEmailAddress));
this.refreshToken$ = this.stravaStore.pipe(select(selectRefreshToken));
this.emailAddress$.pipe(
skipUntil(this.emailAddress$)).subscribe(res => {
if (res) {
this.stravaStore.dispatch(new GetStravaAuthorization(res));
}
});
}