簡體   English   中英

Angular 動態過濾 RxJS 可觀察多個條件

[英]Angular dynamically filter RxJS observable with multiple condition

我想用來自 Angular FireStore 的數據實現動態客戶端過濾。

我有以下服務,它或多或少地工作,但它真的很冗長,我認為它可以改進。 我的問題是filteredFiles$部分,我認為我使用的if邏輯可以通過正確使用RxJs運算符來省略,但我不知道怎么做。

任何幫助,將不勝感激。

謝謝你。

服務:

files$: Observable<FileModel[]>;
public filteredFiles$: Observable<FileModel[]>;

public sourceFilter$ = new BehaviorSubject<string | null>(null);
public extensionFilter$ = new BehaviorSubject<string[] | null>(null);
public channelIdFilter$ = new BehaviorSubject<string | null>(null);
public teamIdFilter$ = new BehaviorSubject<string | null>(null);
public idFilter$ = new BehaviorSubject<string[] | null>(null);
private filesCollectionRef: AngularFirestoreCollection<FileModel>;

constructor(
    private afs: AngularFirestore,
    private userService: UserService
  ) {

this.filesCollectionRef = this.afs.collection<FileModel>('files', ref =>
  ref.where('perm.readers', 'array-contains', this.userService.uid));

this.files$ = this.filesCollectionRef.valueChanges({idField: 'id'});

this.filteredFiles$ = combineLatest([
  this.files$,
  this.extensionFilter$,
  this.channelIdFilter$,
  this.teamIdFilter$,
  this.idFilter$
]).pipe(
  map(([files, extension, channel, teamId, id]) => {
      if (extension === null && channel === null && teamId === null && id === null) {
        return files;
      } else {

        if (channel !== null && extension !== null && id !== null) {          
          return files.filter(
            (file) =>
              file.channel === channel && extension.includes(file.extension) && id.includes(file.id)
          );
        }

        if (extension !== null && id !== null) {          
          return files.filter(
            (file) =>
              extension.includes(file.extension) && id.includes(file.id)
          );
        }

        if (channel !== null && extension !== null) {          
          return files.filter(
            (file) =>
              file.channel === channel && extension.includes(file.extension)
          );
        }

        if (id !== null) {
          return files.filter(
            (file: FileModel) =>
              id.includes(file.id)
          );
        }

        if (extension !== null) {          
          return files.filter(
            (file: FileModel) =>
              extension.includes(file.extension)
          );
        }

        if (channel !== null) {          
          return files.filter(
            (file: FileModel) =>
              file.channel === channel
          );
        }
      }
    }
  )
);

filterByExtension(extensions: string[]) {
    this.extensionFilter$.next(extensions);
}

filterByChannelId(channelId: string | null) {
  this.channelIdFilter$.next(channelId);
}

filterByTeamId(teamId: string | null) {
  this.teamIdFilter$.next(teamId);
}

filterById(id: string[] | null) {
  this.idFilter$.next(id);
}

在模板中:

<li *ngFor="let file of this.fileService.filteredFiles2$ | async">
   <app-display-file [file]="file"></app-display-file>       
</li>

這里可以調整多項內容。

  1. 假設您永遠不會將值null推送到任何可觀察對象,您可以將BehaviorSubject替換為ReplaySubject(1) (緩沖區1 )。 這樣,您不必提供初始值,但仍然能夠緩沖一個值並在訂閱時立即發出它。

  2. 但是,如果您可以推送null ,那么您可以就地使用三元運算符來檢查該值是否已定義。

嘗試以下

files$: Observable<FileModel[]>;
public filteredFiles$: Observable<FileModel[]>;

public sourceFilter$ = new ReplaySubject<string>(1);
public extensionFilter$ = new ReplaySubject<string[]>(1);
public channelIdFilter$ = new ReplaySubject<string>(1);
public teamIdFilter$ = new ReplaySubject<string>(1);
public idFilter$ = new ReplaySubject<string[]>(1);

private filesCollectionRef: AngularFirestoreCollection<FileModel>;

constructor(private afs: AngularFirestore, private userService: UserService) {
  this.filesCollectionRef = this.afs.collection<FileModel>('files', ref =>
    ref.where('perm.readers', 'array-contains', this.userService.uid)
  );
  this.files$ = this.filesCollectionRef.valueChanges({idField: 'id'});

  this.filteredFiles$ = combineLatest(
    this.files$, 
    this.channel$, 
    this.teamId$, 
    this.extension$, 
    this.id$
  ).pipe(map(
    ([files, channel, teamId, extensions, ids]) =>
      files.filter(file => 
        (channel ? file.channel === channel : true) &&
        (teamId ? file.teamId === teamId : true) &&
        (extensions ? extensions.includes(file.extension) : true) &&
        (ids ? ids.includes(file.id) : true)
      )
  ));
}

您可以 go 使用else if而不是多個if

pipe(
  map(([files, extension, channel, teamId, id]) => {
      if (extension === null && channel === null && teamId === null && id === null) {
        return files;
      } else {
        const isChannel = Boolean(channel !== null);
        const isExtension = Boolean(extension !== null);
        const isId = Boolean(id !== null);

        if (isChannel && isExtension && isId) {          
          return files.filter((file) =>
              file.channel === channel && extension.includes(file.extension) && id.includes(file.id));
        } else if (isExtension && isId) {          
          return files.filter(
            (file) => extension.includes(file.extension) && id.includes(file.id));
        } else if (isChannel && isExtension) {          
          return files.filter(
            (file) => file.channel === channel && extension.includes(file.extension));
        } else if (isId) {
          return files.filter((file: FileModel) => id.includes(file.id));
        } else if (isExtension) {          
          return files.filter((file: FileModel) => extension.includes(file.extension));
        } else if (isChannel) {          
          return files.filter((file: FileModel) => file.channel === channel);
        }
      }
    }
  )

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM