首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何从可观察对象中检索值以用于服务API调用

如何从可观察对象中检索值以用于服务API调用
EN

Stack Overflow用户
提问于 2019-03-27 19:16:45
回答 4查看 690关注 0票数 0

我有一个使用ngrx-store的Angular应用程序。我为我的功能组件提供了以下文件

代码语言:javascript
复制
<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 store都是新手,我需要一些帮助来从store中检索一个值(emailAddress),以便在服务API调用中使用。在服务方法中,我可以订阅并通过控制台记录值,但是,当进行服务调用时,该值为空,因此我无法获得数据。

如何在订阅emailAddress选择器的同时调用服务API,以确保值存在。存储中的电子邮件地址只在用户登录时存储一次,该值永远不会更改。

我的组件

代码语言:javascript
复制
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());
    }
}

我的组件选择器

代码语言:javascript
复制
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服务中的方法

代码语言:javascript
复制
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));            

    };

我的效果如下

代码语言:javascript
复制
@Effect()
    getStravaAuthorization$ = this.actions$.pipe(
        ofType<GetStravaAuthorization>(StravaActionTypes.GetStravaAuthorization), mergeMap(() => this.stravaService.getStravaAuthorization()
            .pipe(map((strava: Strava) => new GetStravaAuthorizationSuccess(strava))))
    );

从存储中检索值的电子邮件地址选择器是

代码语言:javascript
复制
export const selectEmailAddress = createSelector(
    selectAuth, (state: AuthState) => {
        if ((state.userDetails === null || state.userDetails === undefined))
            return "";
        else
            return state.userDetails.email
                ;
    }
);

我的控制台日志如下

console.log output

按照建议将代码从服务移动到组件后,我现在在this.emailAddress$上得到一个错误,指出“无法为'new‘选择重载表达式类型不匹配参数emailAddress应该具有可分配给字符串的类型,但它具有可观察的类型

更新的组件代码

代码语言:javascript
复制
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$));
    }
}

更新代码

我的组件

代码语言:javascript
复制
ngOnInit() {
        this.appState
            .pipe(
                select(selectEmailAddress),
                first()
            )
            .subscribe((emailAddress) => {
                this.stravaStore.dispatch(new GetStravaAuthorization(emailAddress)); //dispatch action with the payload containing email address
            });
    }

我的效果

代码语言:javascript
复制
@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)))
        );

我的服务

代码语言:javascript
复制
 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));
        }

行为

代码语言:javascript
复制
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的一部分

代码语言:javascript
复制
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;
}

现在我在更新后的代码中看到了错误

Component error

effect error

EN

回答 4

Stack Overflow用户

发布于 2019-03-27 19:27:39

在下面的代码行中,您将传递this.emailAddress$,假设它是电子邮件地址的值,而它是一个Observable。这就是它行不通的原因。

代码语言:javascript
复制
let getStravaApi = `${AppSettings.CONTACTS_API_HOST}employee/strava?emailaddress=${this.emailAddress$}`;

我强烈建议您从您的组件传递电子邮件,因为该服务在很大程度上不应该访问商店。如果你仍然想在你的服务中订阅状态,你可以这样做:

代码语言:javascript
复制
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的参数。例如,类似于:

代码语言:javascript
复制
export class MyAction {
  readonly type = MY_TYPE;
  constructor(public payload: string) {}
}

组件:

代码语言:javascript
复制
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
        });
    }
}

效果:

代码语言:javascript
复制
  @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)))
    );

服务:

代码语言:javascript
复制
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));            

    };
票数 0
EN

Stack Overflow用户

发布于 2019-03-27 19:28:50

在构建请求时,您似乎正在尝试将可观察对象用作字符串值。

代码语言:javascript
复制
let getStravaApi = `${AppSettings.CONTACTS_API_HOST}employee/strava?emailaddress=${this.emailAddress$}`;`

有几种方法可以实现这一点,我将分享async/await路线。

您可以通过使用.toPromise()方法将其转换为promise来等待可观察对象的结果。

代码语言:javascript
复制
public async getStravaAuthorization(): Observable<Strava> {
  ...
  const emailAddress = await this.emailAddress$.toPromise();
  ...
}

票数 0
EN

Stack Overflow用户

发布于 2019-03-27 20:58:59

您应该从getStravaAuthorization效果中选择电子邮件地址。因此,您可以从您的组件发送: new GetStravaAuthorization()而不带电子邮件,但当电子邮件不为空或未定义时,效果将从您的选择器获取电子邮件,并将其传递给我们的服务。

代码语言:javascript
复制
       @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))))
    );
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55375899

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档