【问题标题】:How to sort by date (asc or desc) an Observable in Angular components如何按日期(asc 或 desc)对 Angular 组件中的 Observable 进行排序
【发布时间】:2020-03-06 03:46:38
【问题描述】:

我想知道如何按日期对组件中数组中的数据进行排序,我有以下结构:

模板:

<div>
  <button (click)="sortByDate()">
    Sort by date
  </button>
</div>
<div *ngFor="let rally of rallies$ | async">
    <img src="{{ rally.icon }}" />
</div>

组件:

rallies$: Observable<Rally>;

  constructor(private ralliesService: RalliesService) {}

  ngOnInit() {
    this.getRallies();
  }

  getRallies() {
    this.rallies$ = this.ralliesService.getRallies();
  }

  sortRalliesByDate() {
    ???
  }

问题是我明白了如何在订阅 observable 后使用组件中的数组进行操作,但现在我想直接在 observable 中操作并使用模板中的异步管道。

【问题讨论】:

    标签: angular rxjs observable


    【解决方案1】:

    终于这样解决了:

    sortRalliesByDateDesc() {
            this.rallies$ = this.rallies$.pipe(map((rallies => rallies.sort((a, b) => new Date(b.startDate).getTime() - new Date(a.startDate).getTime()))))
    }
    
      sortRalliesByDateAsc() {
            this.rallies$ = this.rallies$.pipe(map((rallies => rallies.sort((a, b) => new Date(a.startDate).getTime() - new Date(b.startDate).getTime()))))
    }
    

    Stackblitz 示例:

    https://stackblitz.com/edit/angular-glwwvv

    【讨论】:

      【解决方案2】:

      你需要使用 as 操作符引用从 observable 发出的值。然后你可以将它传递给排序函数。

      <ng-container *ngIf="rallies$ | async as rallies">
        <div>
          <button (click)="sortByDate(rallies)">
            Sort by date
          </button>
        </div>
        <div *ngFor="let rally of rallies">
            <img src="{{ rally.icon }}" />
        </div>
      </ng-container>
      

      并让排序函数将模板变量作为参数。

      sortByDate = rallies => rallies.sort((a, b) => a.date - b.date);
      

      这个解决方案的问题是你正在改变由 rallies$ observable 发出的反弹。我使用一个克隆管道,在分配给模板变量之前克隆发出的值。

      *ngIf="rallies$ | async | clone as rallies"
      

      这样排序功能不会产生任何副作用。

      import { Pipe, PipeTransform } from '@angular/core';
      
      import { clone } from './clone';
      
      @Pipe({
        name: 'clone'
      })
      export class ClonePipe implements PipeTransform {
      
        transform(value: any): any {
          return clone(value);
        }
      }
      

      还有克隆功能

      export const clone = (obj: any) =>
        Array.isArray(obj)
          ? obj.map(item => clone(item))
          : obj instanceof Date
          ? new Date(obj.getTime())
          : obj && typeof obj === 'object'
          ? Object.getOwnPropertyNames(obj).reduce((o, prop) => {
              o[prop] = clone(obj[prop]);
              return o;
            }, {})
          : obj;
      

      克隆意味着我们没有对可能使用来自 rallies$ observable 数据的其他组件造成任何副作用。

      【讨论】:

        【解决方案3】:

        假设您想按属性createdAt 进行排序,您可以简单地像这样映射它:

        sortRalliesByDate() {
          return this.rallies$
            .pipe(
              map(rallies => rallies.sort((a, b) => a.createdAt - b.createdAt)
            );
        }
        

        【讨论】:

        • 我之前试过这个,但它总是抛出错误“Property 'sort' does not exist on type 'Rally'”
        • @Jgascona 我认为rallies$Observablle&lt;Rally[]。如果不是,那是什么?
        • 哇...我实际上定义为Observablle&lt;Rally&gt; ...我想你明白了
        • 非常感谢,您帮我解决了很多问题
        猜你喜欢
        • 2019-10-06
        • 2013-08-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-06
        • 1970-01-01
        • 2021-12-13
        • 1970-01-01
        相关资源
        最近更新 更多