* ng用于通过可计算属性的可观察列表排序

时间:2019-02-05 10:59:45

标签: angular firebase ionic-framework

首先,我是法国人,所以我为我的英语道歉...

我想订购带有* ngFor的Observable。

这是我的代码:

<app-root></app-root>

我从firebase获取所有数据。

接下来,我将执行* ngFor显示:

base.OnActionExecuted()

我的问题是我想用距离值对列表进行排序(根据coordX和coordY的函数进行计算)... 目前,列表以字母顺序显示。

非常感谢您的支持!

3 个答案:

答案 0 :(得分:1)

在使用字符串插值语法({{}})调用函数时,就性能而言,您编写的代码非常昂贵

我建议您在组件本身中执行此操作。试试看:

this.allBoulangeries$ = this.allBoulangeriesService.getAllBoulangeries()
  .pipe(
    map(boulangeries => boulangeries.map(boulangerie => {
      return { 
        ...boulangerie, 
        distance: this.distanceTo(boulangerie.coordX, boulangerie.coordY, this.latitude, this.longitude) 
      };
    })),
    map(boulangeries => boulangeries.sort((b1, b2) => b1.distance - b2.distance ))
  );

答案 1 :(得分:0)

您可以创建一个custom pipe来按距离进行计算和排序:

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({name: 'orderByDistance'})
export class OrderByDistancePipe implements PipeTransform {
  transform(boulangeries: Boulangerie[], latitude: number, longitude: number): Boulangerie[] {
    return boulangeries.sort((a, b) => {
        return distanceTo(b.coordX, b.coordY, latitude, longitude) -
               distanceTo(a.coordX, a.coordY, latitude, longitude);
    });
  }
}

此管道返回您订购的Boulangeries列表。 然后,可以通过在管道之前将数组传递,并在:之后给出纬度和经度参数,来在数组上使用它。

<ion-card *ngFor="let boulangerie of ((allBoulangeries$ | async) | orderByDistance:latitude:longitude)"  tappable (click)="viewDetails(boulangerie)">
    <div padding>
        <b>{{ boulangerie.name }}</b>
        <p>{{ boulangerie.address }}<br>
           {{ boulangerie.cp }} {{ boulangerie.ville }}</p>
        <p>Distance: {{ distanceTo(boulangerie.coordX, boulangerie.coordY, latitude, longitude) }}</p>
    </div>
</ion-card>

另一种方法是通过将数组传递到可观察对象以返回可观察到的有序数组来对组件中的数组进行排序:

this.boulangeriesOrdered$ = this.boulangeries.pipe(
    map(arr => arr.sort((a, b) =>
        distanceTo(b.coordX, b.coordY, latitude, longitude) -
        distanceTo(a.coordX, a.coordY, latitude, longitude)
    ))
);

然后,您可以使用此可观察值代替Boulangeries $。

在性能方面,这两种方法都具有可比性,因为每次可观察对象生成新数组时,排序都会中断。

答案 2 :(得分:0)

解决方案1:假设将这些对象推入火力点时可以使用经度和纬度

当您将boulangerie推送到Firebase时,请将计算出的距离添加到对象,然后再将其推送到数据库。当您获得boulangeries的集合时,这比对每个对象执行此操作更为有效。

查询boulangeries的集合时,请在对数据库的调用上使用orderBy('distance')(假设您的Firebase数据库依赖项称为db):

如果使用实时数据库,您的BoulangerieService中的方法将如下所示:


getAll(): Observable<Boulangerie[]> {
    db.collection('items', ref => ref.orderBy('distance')).valueChanges();
}

在Firestore中,它看起来像这样:


getAll(): Observable<Boulangerie[]> {
    this.db.list('/boulangeries', ref => ref.orderByChild('distance')).valueChanges()
}

然后,如果您需要按字母顺序或任何其他属性排序,则可以改编其他答案中提供的管道之一,以很好地完成此操作:)

解决方案2:如果您在推向火力点时无法使用长和纬度

我强烈建议您在服务而不是组件中执行以下操作-这是一种更好的做法,因为您将数据的操作与组件中的数据表示分开。这也是使用RxJS的更好方法。请注意,您需要从RxJS导入map运算符以执行以下操作。

确保在要调用Firebase的服务或组件中可以使用经度和纬度以及distanceTo()函数,并尝试:


// If using firestore:

getAll(): Observable<Boulangerie[]> {
    this.db.list('/boulangeries', ref => ref.orderByChild('distance')).valueChanges()
    .pipe(
        map((boulangeries: Boulangerie[]) => {
            boulanderies.forEach((boulangerie) => {
                boulangerie.distance = distanceTo(boulangerie.coordX, boulangerie.coordY, latitude, longitude)
            })
        })
    )
}