Отфильтруйте массив Observable, чтобы получить один результат - PullRequest
0 голосов
/ 17 марта 2019

Я делаю веб-приложение на Angular 6 и angularfire2.В моем сервисе у меня есть массив Observable, и я хочу отфильтровать его, чтобы получить только один результат.Внутри всех документов есть карта с именем moderatorAssigned со свойством id, этот идентификатор - uid пользователя в firebase.

У меня есть компании, у каждой компании есть офисы, а у офиса естьназначен модератором, и я хотел бы вернуть в свой компонент офис, в который был назначен пользователь.

export interface Company {
  name: string;
  emailAddress: string;
  typeOfService: string;
  offices: Office[];
}

export interface CompanyId extends Company {
  id: string;
}

export interface Office {
  id: string;
  name: string;
  address: string;
  moderatorAssigned: {
    firstName: string;
    id: string;
    lastName: string;
  };
}

Компонент

export class SeeTurnsComponent implements OnInit {

  officeAssigned: Observable<Office>;

  constructor(private companyService: CompanyService,
              private authService: AuthService) {
  }

  ngOnInit() {
    const userId = this.authService.getUserUid();
    this.officeAssigned = this.companyService.getOfficeAssigned(userId);
  }

}

Шаблон

<div *ngIf="officeAssigned | async as office">
    {{office.id}}
  </div>

Сервис

private companiesCollection: AngularFirestoreCollection<Company>;
companies: Observable<CompanyId[]>;

  constructor(private afs: AngularFirestore) {
    this.companiesCollection = afs.collection<Company>(
      config.collection_companies,
      ref => ref.orderBy('createdAt', 'desc')
    );

    this.companies = this.companiesCollection.snapshotChanges().pipe(
      map(actions => actions.map(a => {
        const data = a.payload.doc.data() as Company;
        const id = a.payload.doc.id;
        return {id, ...data};
      }))
    );
  }

getOfficeAssigned(userId: string): Observable<Office> {
    this.companies.pipe(
      map(companies => companies.filter(company => {
        company.offices.filter(office => {
          console.log('comparing...');
          if (office.moderatorAssigned && office.moderatorAssigned.id === userId) {
            console.log('office found...');
            return office;
          } else {
            console.log('no office assigned...');
            return of(null);
          }
        });
      }))
    );

    return of(null);
  }

В результате нет данных, возможно, я что-то не так делаю.

Моя цель - поискать внутри companies: Observable<CompanyId[]> в моем сервисе и вернуть офис, в котором находится пользовательбыл назначен для отображения данных в шаблоне.

1 Ответ

2 голосов
/ 17 марта 2019

В вашем коде много проблем:

getOfficeAssigned(userId: string): Observable<Office> {
    this.companies.pipe(
      map(companies => companies.filter(company => {
        company.offices.filter(office => {
          console.log('comparing...');
          if (office.moderatorAssigned && office.moderatorAssigned.id === userId) {
            console.log('office found...');
            return office;
          } else {
            console.log('no office assigned...');
            return of(null);
          }
        });
      }))
    );

    return of(null);
}

Во-первых, ваш метод всегда возвращает of(null). Это бессмысленно. Вы хотите вернуть наблюдаемое, полученное преобразованием this.companies.

Код должен выглядеть следующим образом:

getOfficeAssigned(userId: string): Observable<Office> {
    return this.companies.pipe(
      map(companies => this.findOfficeWithAssignedUserId(companies, userId))
    );
}

Затем реализуйте метод findCompanyWithAssignedUserId и протестируйте его. Обратите внимание, что для этого не нужно использовать какой-либо связанный с Observable тип или метод. Требуется только find элемент этого массива. Это должно выглядеть как

findOfficeWithAssignedUserId(companies: Array<Company>, userId: string): Office {
    const company = companies.find(c => 
      c.offices.some(office =>
        office.moderatorAssigned.id === userId
      )
    );
    return company && company.offices.find(office =>
      office.moderatorAssigned.id === userId
    );
}

Код был бы лучше с flatMap, но flatMap все еще экспериментальный. Есть другие способы, более эффективные, чтобы сделать этот цикл, но это должно быть достаточно быстро и дать вам идею.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...