Как справиться с асинхронной природой Rx JS Наблюдаемые внутри Angular - PullRequest
1 голос
/ 27 апреля 2020

Я новичок в Angular и архитектуре Observables, и у меня возникают проблемы с запуском функций с асинхронным кодом.

В приведенном ниже коде я использую библиотеку AngularFire для получения информации от база c База данных Firebase в реальном времени. Однако, когда я вызываю функцию searchForCompany() из одного из моих компонентов, наблюдаемая не загружает необходимые данные мгновенно, то есть элементы HTML моего компонента загружаются неправильно. Я неправильно использую архитектуру Observables?

import { SubscriptionData } from './interface'
import { Injectable } from '@angular/core';
import { AngularFireDatabase, AngularFireList } from '@angular/fire/database'

@Injectable({
  providedIn: 'root'
})

export class SubscriptionService {
  private dbRead: SubscriptionData[];
  private subscriptionData = new SubscriptionData;
  private databasePath = "/companies";
  private databaseRef: AngularFireList<SubscriptionData>;

  constructor(private _database: AngularFireDatabase) {
    this.databaseRef = _database.list(this.databasePath);
  }

  searchForCompany(service:String) {
    for (let key of this.dbRead) {
      //Search for name of a company in the Firebase database
      if (key.name == service) {
        this.subscriptionData=key;
        return;
      }
    }

  readDatabase() {
    this.databaseRef.valueChanges().subscribe(data=> {
      this.dbRead = data;
    })
  }
}

1 Ответ

1 голос
/ 27 апреля 2020

думать о наблюдаемом, как о потоке, который предоставляет данные. Ваш компонент должен подписаться на этот поток. Затем компонент будет получать каждое новое значение из потока.

Пример здесь :

@Component({
  selector: 'app-users-listing',
  templateUrl: './users-listing.component.html',
  styleUrls: ['./users-listing.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class UsersListingComponent {

  // THIS IS A "STREAM" AND YOU NEED TO SUBSCRIBE TO IT IN THE TEMPLATE OR INSIDE CODE
  users$: Observable<UserInterface[]> = this.activatedRoute.data.pipe(
    map(data => data.users),
  );

  constructor(
    private activatedRoute: ActivatedRoute,
  ) { }

}

Давайте подпишемся на users$ внутри шаблона

<mat-list>
  <!-- "users$ | async" creates a subscription  -->
  <mat-list-item *ngFor="let user of (users$ | async)">
    <h3 matLine> {{ user.first_name + ' ' + user.last_name }} </h3>
    <p matLine>
      <span> {{user.email}} </span>
    </p>
  </mat-list-item>
</mat-list>

По вашему примеру. Попробуйте изменить свой сервис, чтобы он возвращал Observable из метода и подписывался на него в вашем компоненте. Это может быть как

searchForCompany () {
  return this.databaseRef.valueChanges()
}

И подписаться на него в компоненте, преобразовать полученные данные и т. Д. c. Это может выглядеть так:

export class MyComponent {
  constructor (private service: SubscriptionService) {}

  ngOnInit(): void {
    this.service.searchForCompany().pipe(
      // SOME ADDITIONAL LOGIC
      // --> WRITE SOME CODE TO DESTROY SUBSCRIPTION HERE <---
    ).subscribe();
  }
}

ИЛИ создать свойство класса - можно наблюдать. И подпишитесь на него в шаблоне, используя async pipe

export class MyComponent {

  propert$ = this.service.searchForCompany().pipe(
    // SOME ADDITIONAL LOGIC
  )
  constructor (private service: SubscriptionService) {}
}

Надеюсь, это поможет.

...