简体   繁体   English

Angular Observable订阅回退?

[英]Angular Observable subscription fallback?

I'm using Angular 4 and I have a component that lives at the 'player/:id' route in my application. 我正在使用Angular 4,我有一个组件,它位于我的应用程序中的'player /:id'路径中。 When the player navigates to this route from within the application I use a currentPlayerService to sync the current player within the app. 当玩家从应用程序内导航到此路线时,我使用currentPlayerService来同步应用程序中的当前玩家。 This works great with the below code. 这适用于以下代码。

this.currentPlayerService.getPlayer()
  .subscribe((player) => this.currentPlayer = player);

However, when the application loads directly to the 'player/:id' route (from an external link) I can comment out the above and use the code below to set the currentPlayer from the route params. 但是,当应用程序直接加载到'player /:id'路径(来自外部链接)时,我可以注释掉上面的内容并使用下面的代码从路径参数设置currentPlayer。

this.route.params.subscribe(params => {
  this.playerService.getPlayer(params.id)
    .subscribe((player) => {
      this.currentPlayer = player;
      this.currentPlayerService.setPlayer(player);
    });
 });

What I'd like to do (and am having difficulty finding the "reactive function programming" way of saying) is to load the player from the params only if this.currentPlayerService.getPlayer() doesn't have a value on load. 我想做的事情(并且很难找到“反应函数编程”的说法)只有当this.currentPlayerService.getPlayer()在加载时没有值时才从params加载播放器。 I'm having a hard time conceiving of a way to use the Observable in some kind of logic control flow, so any help would be appreciated. 我很难想到在某种逻辑控制流程中使用Observable的方法,所以任何帮助都会受到赞赏。

Thanks! 谢谢!

Observables itself is stateless. 可观测量本身是无国籍的。 To keep track of a value (or current value), you will need to use either Subject or BehaviorSubject . 要跟踪值(或当前值),您需要使用SubjectBehaviorSubject

In your currentPlayerService , create a BehaviorSubject called playerBSubject : currentPlayerService ,创建一个名为playerBSubjectBehaviorSubject

export class CurrentPlayerService{
  public playerBSubject: BehaviorSubject<any>;//can be type of Player if you have such type
  constructor(){
    this.playerBSubject = new BehaviorSubject({})//any value that you want to initialize
  }

  getPlayer(){
    //do your logic here, whatever that is.
    //I am using an Observable.of to mimic a http request
    Observable.of({})
      .subscribe((player)=>{
      this.playerBSubject.next(player)//this will update the subject with the latest value
    });
    return this.playerBSubject.asObservable();
  }

}

Note that the .next() method will update the values of your subject, and you can return it as an observable using .asObservable() . 请注意, .next()方法将更新主题的值,您可以使用.asObservable()将其作为可观察对象返回。

Now, in your component controller, you can check if your BehaviourSubject exist (or has the value you want), and only call playerService.getPlayer() if need to. 现在,在组件控制器中,您可以检查您的BehaviourSubject存在(或具有您想要的值),并且只在需要时调用playerService.getPlayer()

this.route.params.subscribe(params => {
    //check if BehaviorSubject exist or not
    if (this.currentPlayerService.playerBSubject.getValue() === {}) {
        this.playerService.getPlayer(params.id)
            .subscribe((player) => {
                this.currentPlayer = player;
                this.currentPlayerService.setPlayer(player);
            });
    }
});

Suggestions: 建议:

I am not sure why you need two service namely currentPlayerService and playerService . 我不确定为什么你需要两个服务,即currentPlayerServiceplayerService If your currentPlayerService is just to keep track of "current" value of the player, then you do not need it at all, should you use BehaviorSubject to keep track of your current player. 如果您的currentPlayerService只是为了跟踪播放器的“当前”值,那么您根本不需要它,如果您使用BehaviorSubject来跟踪当前播放器。 All of them can boil down into one single service. 所有这些都可以归结成一个单一的服务。

export class PlayerService {
    public playerBSubject: BehaviorSubject<any>;

    constructor() {
        this.playerBSubject = new BehaviorSubject({})
    }

    getPlayer(id) {
        Observable.of({id}) // implement your own logic
            .subscribe((player) => {
                this.playerBSubject.next(player)
            });
        return this.playerBSubject.asObservable();
    }

    setPlayer(id) {
        return Observable.of({id})//implement your own logic
            .subscribe(newPlayer => this.playerBSubject.next(newPlayer))
    }
}

And in your controller if you want to get the current value you can just do: 在您的控制器中,如果您想获得当前值,您可以这样做:

this.currentPlayer = this.playerService.playerBSubject.getValue();

And with a little help of asObservable you can do this: asObservable帮助下你可以这样做:

this.playerService
    .asObservable()
    .subscribe(player => {
        if (player === {}) {
            this.route.params.subscribe(params => {
                this.playerService.getPlayer(params.id); //voila, your player is updated
            })
        }
        //remember to update the value
        this.currentPlayer = player
    })

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM