【问题标题】:How to loop through (forEach) on an Observable which has been subscribed by the template如何在模板订阅的 Observable 上循环 (forEach)
【发布时间】:2023-03-24 04:22:02
【问题描述】:

我有一个 AFS observable,我可以像这样在前端显示它:

constructor(
    public fb: FirebaseProvider, 
) {
    this.group = this.navParams.get('group');
    this.contactsList = this.fb.getContactsByGroup(this.group.id);
}

我的脸书服务:

getContactsByGroup(groupId: string):Observable<Contact[]> {
    return this.afs.collection<Contact>(`groups/${groupId}/contacts`).valueChanges();
}

然后是我的模板:

<single-contact-list-item 
    [contactId]="contact.id" 
    (goToModalEvent)="onGoToModal($event)"
    *ngFor="let contact of contactsList | async">
</single-contact-list-item>

现在我有一个文本区域,提交时会触发一个事件。我想要做的是遍历 Observable (contactsList) 中的每个项目并获取一个属性,例如:

public sendSMS(): void {
    this.contactsList.forEach(contact => {
        console.log(contact.number); // nothing!
    })
    //this.deviceProvider.sendSMS(this.contactsList, this.message);
}

我觉得问题在于通过在模板中使用异步管道,Observable 已经被订阅了。任何帮助表示赞赏。

【问题讨论】:

    标签: javascript angular rxjs observable


    【解决方案1】:

    您需要在组件中的变量中手动获取 Observable 的结果。

    constructor(
         public fb: FirebaseProvider, 
    ) {
         this.group = this.navParams.get('group');
         this.fb.getContactsByGroup(this.group.id).subscribe(list => 
            this.contactsList = list);    
      }
    

    并更改您的模板以仅在contactList 可用时呈现。并遍历列表。

    <ng-container *ngIf="contactsList">
        <single-contact-list-item 
        [contactId]="contact.id" 
        (goToModalEvent)="onGoToModal($event)"
        *ngFor="let contact of contactsList">
        </single-contact-list-item>
    <ng-container>
    

    通过执行此操作,您的函数 sendSms 将按原样工作并获取联系人列表。

    public sendSMS(): void {
        this.contactsList.forEach(contact => {
          console.log(contact.number); // WORKING!!!!
        })
        //this.deviceProvider.sendSMS(this.contactsList, this.message);
      }
    

    【讨论】:

    • 我喜欢这个答案,因为我不需要重新获取 observable :) 谢谢
    【解决方案2】:

    您需要先订阅Observable 才能访问数据流,然后执行循环。试试

    public sendSMS(): void {
        this.contactsList.subscribe(lists=>{
            lists.forEach(contact=>{
                console.log(contact.number);
            }
        }
      }
    

    【讨论】:

    • 不是一个好方法。这将使第二个订阅者在内存中。每次更改都会调用 2 个函数。
    【解决方案3】:

    您可以重复使用包含数组的 observable 并对流执行一些操作以提取有趣的数据。如果它只是针对与您的数据相关的副作用,您可以使用点击运算符并在里面执行您的 forEach。

     public sendSMS(): void {
        this.contactsList.pipe(
          tap(contactArray => {
             contactArray.forEach(contact => {
               // Do side effect operations with your array
             });
          }),
          // execute only once and complete the observable
          take(1)
        ).subscribe();
     }
    
       this.deviceProvider.sendSMS(this.contactsList, this.message);
    

    【讨论】:

      【解决方案4】:

      您必须重新获取数据以进行迭代,因为contactsList 可能已经被使用了。所以需要再次调用this.fb.getContactsByGroup(this.group.id)

      public sendSMS(): void {
        // use .first() to just process once
        this.fb.getContactsByGroup(this.group.id).first().subscribe(contacts => {
          contacts.forEach(contact => {
            console.log(contact.number);
          });
          // <>
        })
        
        // notice the code above is asynchronous, so if the line below
        // depends on it, place it on the line marked with "// <>" above
        //this.deviceProvider.sendSMS(this.contactsList, this.message);
      }

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-30
        • 2018-02-02
        • 2021-03-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多