如何在 Angular 中继续之前等待来自服务的新数据

How to wait for new data from service before proceeding in Angular

我有两个使用服务共享数据的组件:

export class ShareDataService {

  msg: BehaviorSubject<string>;

  constructor(
  ) { 
    this.msg = new BehaviorSubject("Default Message")
  }

  changeMessage(message: string) {
    this.msg.next(message)
  }
}

第一个组件用作路由器,当我单击一个名称时,它会使用其 ID 重定向到该名称的配置文件。我导入上面创建的共享数据服务,当单击名称时它会触发 de sendData() 函数,该函数获取被单击元素的 ID 并将其作为参数传递给服务 changeMes​​sagge() 函数:

  constructor(
    private _data: ShareDataService
  ) { }
  
  message: string = "";

  ngOnInit(): void {


    this._data.msg.subscribe(new_msg => this.message = new_msg)
  }

  sendData() {
    var self = this
    $("ul.users-list").on("click", ".user", function(event) {
      self._data.changeMessage(event.target.id)
    });
  }
}

之后,当它重定向到新组件时,这个新组件也从服务中导入数据:

  message: string = "";

  constructor(
    private _http: HttpClient,
    private _data: ShareDataService,
    private _router: Router
    ) { }

async ngOnInit() {
    this._data.msg.subscribe(new_msg => this.message = new_msg)

    await new Promise(r => setTimeout(r, 1)); // Sleeps 1ms so it can load message

    if (this.message === "Default Message") { // Returns to landing if no user loaded
      this._router.navigateByUrl("/landing");
      return
    }
    this._http.get<UserInterface>(`https://jsonplaceholder.typicode.com/users/${this.message}`)
    .subscribe((data: UserInterface) => this.user = data)
  }

如您所见,它订阅了该服务并获取了 messagge 的值,当我在另一个组件上单击名称时,该值应该已更改。问题是,它首先没有检测到变化,我必须使用新的 Promise() 函数让它休眠 1 毫秒,以便它可以从服务加载新的 messagge 值,然后继续。有什么办法可以让它等待订阅完成加载新消息而无需使用 Promise 1 毫秒?已经尝试在分配消息后将代码放入订阅中。

我看到多个问题

  1. 变量this.message被异步赋值。发送 HTTP 请求时,尚未为其分配值。您需要使用像 switchMap 这样的高阶映射运算符来从一个可观察对象映射到另一个。
import { switchMap } from 'rxjs/operators';

this._data.msg.pipe(
  switchMap(message => 
    this._http.get<UserInterface>(`https://jsonplaceholder.typicode.com/users/${message}`)
  )
).subscribe((data: UserInterface) => this.user = data)

您可以查看我的 post ,了解有关处理多个相互依赖的可观察量的简要信息。

  1. await new Promise(r => setTimeout(r, 1)); 看起来不雅,但超时时间很小。有了上面的映射运算符,就不再需要它了。

  2. 避免在 Angular 中使用 jQuery。 jQuery 中的几乎所有内容都可以直接在 Angular 中完成。混合使用它们可能会导致以后进行维护。

更新:return有条件地观察

根据您的情况,您可以使用带有 new Observable() 构造的 RxJS iif 函数来 return HTTP 请求或执行其他操作并根据条件关闭可观察对象。

尝试以下方法

import { iif, EMPTY, Observable } from 'rxjs';
import { switchMap } from 'rxjs/operators';

this._data.msg.pipe(
  switchMap(message => 
    iif(
      () => message === "Default Message",
      new Observable(subscriber => {
        this._router.navigateByUrl("/landing");
        subscriber.complete();
      }),
      this._http.get<UserInterface>(`https://jsonplaceholder.typicode.com/users/${message}`)
    )
  )
).subscribe((data: UserInterface) => this.user = data)