【问题标题】:How to wait for new data from service before proceeding in Angular如何在继续使用 Angular 之前等待来自服务的新数据
【发布时间】:2021-09-08 02:23:50
【问题描述】:

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

export class ShareDataService {

  msg: BehaviorSubject<string>;

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

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

第一个组件用作路由器,当我单击一个名称时,它会使用其 ID 重定向到该名称的配置文件。我导入了我在上面创建的共享数据服务,当单击一个名称时,它会触发 de sendData() 函数,该函数获取单击元素的 id 并将其作为参数传递给 service 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() 函数让它休眠 1ms,以便它可以从服务加载新的消息值,然后继续。有什么方法可以让它等待订阅完成加载新消息而不使用 Promise 1ms?已经尝试在分配消息后将代码放入订阅中。

【问题讨论】:

    标签: javascript html angular async-await routes


    【解决方案1】:

    我发现多个问题

    1. 变量this.message 是异步分配的。在发送 HTTP 请求时,它还没有被赋值。您需要使用像 switchMap 这样的高阶映射运算符从一个 observable 映射到另一个。
    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)
    

    您可以查看我的帖子 here,了解有关处理多个相互依赖的 observable 的简要信息。

    1. await new Promise(r =&gt; setTimeout(r, 1)); 看起来不优雅,无论超时时间有多短。使用上面的映射运算符,它应该不再需要了。

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

    更新:有条件地返回 observable

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

    试试下面的

    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)
    

    【讨论】:

    • 非常感谢它就像一个魅力,我还将删除 jQuery 并将所有内容转换为 Angular 的东西。您是否有机会使用我使用的 id 条件更新您的答案?我尝试以与订阅相同的方式实现它,但似乎不兼容
    • @JavierJerez:如果您的意思是针对"Default Message" 的条件,请查看发布的更新是否有帮助。
    • 你是个天使,唯一的问题是在subscriber.complete() 后面少了一个")"。下一行应该是“})”,而不仅仅是“},”
    • @JavierJerez:谢谢我已经包含它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-26
    • 2021-11-15
    相关资源
    最近更新 更多