如何重新排序组件中的ngFor项目?角2+

时间:2018-09-05 10:56:31

标签: angular sorting

我对Angular还是很陌生,所以这可能是一个简单的解决方法。

目前,我有3种不同的卡被API调用。然后,我使用* ngFor遍历这些项目并为每个项目创建一张卡片,如下所示:

<div *ngFor="let exploreCard of exploreCards" class="col-sm">
                    <div class="card three-col">
                        <img class="card-img-top" [src]="exploreCard.ImageUrl" alt="Card image cap" />
                        <div class="card-body">
                            <h5 class="card-title">{{exploreCard.Title}}</h5>
                            <p class="card-text">{{exploreCard.Description}}</p>
                            <p>{{exploreCard.Sequence}}</p>
                        </div>
                   </div>
 </div>

您将看到我已打印出一个序列号。现在,我的json现在正处于坐姿,以便API检索它时,它会按3 , 2 , 1的顺序返回。

我想按1 , 2 , 3的顺序退回。但是我知道我可以使用管道,但是我需要它尽快运行。我也不想只是颠倒退货的顺序,因为这对于以后的添加是不可持续的。

这是组件中初始化时运行的代码:

this.exploreService.getExploreCards()
            .subscribe(z => {
                this.exploreCards = z;
                if (this.exploreCards != null && this.exploreCards.length > 0) {
                    this.showLoader = false;
                }
            })

exploreCards看起来像这样:

private exploreCards: ExploreCard[];

有人知道如何通过组件中的逻辑实现正确的排序吗?

谢谢。

编辑:

这是我的getExploreCards()方法:

public getExploreCards(): BehaviorSubject<ExploreCard[]> {
        if (this.exploreCards === null) {
            this.exploreCards = new BehaviorSubject<ExploreCard[]>(null);
            this.http.get(`${this.baseUrl}api/Explore/GetExploreCards`).pipe( 
                retry(3) 
            )
                .subscribe((x: ExploreCard[]) => this.exploreCards.next(x));

        }
        return this.exploreCards;
    }

2 个答案:

答案 0 :(得分:1)

从服务中检索卡片时,可以对其进行排序:

this.exploreService.getExploreCards()
            .subscribe(z => {
                if(z != null) {
                    this.exploreCards = z.sort((a,b) => a.Sequence - b.Sequence);
                }
            })

或者当卡片总是要分类时,我会将分类放在服务中。

或者您可以编写排序管道;)

您还可以使用一些实用程序功能代替本地javascript,例如。从lodash到按属性排序:

_.sortBy(cards, card => card.Sequence );

顺便说一句。您不应该在订阅中设置this.showLoader = false;,而应该在finally运算符中设置,这样,当服务调用失败时,加载程序就不再可见。

答案 1 :(得分:0)

您不应在组件中执行此操作,而应在getExploreCards()方法中执行此操作:

getExploreCards(): Observable<ExploreCard[]> {
  this.http.get('link/to/cards').pipe(
    tap((cards) => cards.sort((a, b) => a.Sequence - b.Sequence))
  )
}

此外,考虑使用async管道,这将消除取消订阅组件的必要性。否则,您将具有挂起的订阅,并且随之而来的是内存泄漏。例如,这将是您的html,然后:

<div *ngIf="!(exploreCards$ | async)" class="loader"></div>

<div *ngFor="let exploreCard of exploreCards$ | async" class="col-sm">
 <!-- the rest -->
</div>

您的问题就是这样:

readonly exploreCards$: Observable<ExploreCard[]> = this.exploreService.getExploreCards();

但这完全取决于您:)

-编辑-

要更新您的方法并简化逻辑,可以使用rxjs中的shareReplay()运算符:

private exploreCards = this.http.get(`${this.baseUrl}api/Explore/GetExploreCards`).pipe( 
  retry(3),
  tap((cards) => cards.sort((a, b) => a.Sequence - b.Sequence)),
  shareReplay() 
)

public getExploreCards(): Observable<ExploreCard[]> {
  return this.exploreCards;
}

如果您坚持使用BehaviourSubject,则可以使用以下方法:

public getExploreCards(): BehaviorSubject<ExploreCard[]> {
  if (this.exploreCards === null) {
    this.exploreCards = new BehaviorSubject<ExploreCard[]>(null);
    this.http.get(`${this.baseUrl}api/Explore/GetExploreCards`).pipe( 
      retry(3),
      tap((cards) => cards.sort((a, b) => a.Sequence - b.Sequence)) 
    ).subscribe((x: ExploreCard[]) => this.exploreCards.next(x));
  }

  return this.exploreCards;
}

但是请注意,这非常“反模式”,并且为挂起的订阅留有空间。仅仅因为您的团队使用了它,并不意味着这是正确的方法;)只是我的2c。