Tri des colonnes de table dans Angular

Aug 26 2020

J'essaye de rendre mes colonnes de table triables. J'ai trouvé ce tutoriel ici:https://www.youtube.com/watch?v=UzRuerCoZ1E&t=715s

En utilisant ces informations, je me suis retrouvé avec ce qui suit:

Un tuyau qui gère le tri

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

    @Pipe({
      name: 'sort',
      pure: true
    })
    export class TableSortPipe implements PipeTransform {
    
      transform(list: any[], column:string): any[] {
          let sortedArray = list.sort((a,b)=>{
            if(a[column] > b[column]){
              return 1;
            }
            if(a[column] < b[column]){
              return -1;
            }
            return 0;
          })
        return sortedArray;
      }
    
    }

Voici le composant qui m'aide à construire ma table. Ici, je définis la variable sortedColumn.

import { NavbarService } from './../navbar/navbar.service';
import { LiveUpdatesService } from './live-updates.service';
import { Component, OnInit } from '@angular/core';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-live-updates',
  templateUrl: './live-updates.component.html',
  styleUrls: ['./sass/live-updates.component.scss']
})
export class LiveUpdatesComponent implements OnInit{
  stocks$: Observable<any[]>; sortedColumn: string; constructor(private updatesService: LiveUpdatesService, public nav: NavbarService) { this.stocks$ = this.updatesService.getStocks();
  }

  ngOnInit() {
    this.nav.show();
  }
}

Voici mon fichier modèle. Comme vous pouvez le voir, j'ai attaché mon sorttuyau à ma boucle, crachant les lignes du tableau. Il convient de noter que la façon dont je rend le tableau diffère de la vidéo. Par exemple, ses données sont stockées dans un tableau, mais les miennes sont stockées sur Firebase. Il rend sa table dynamiquement, mais la mienne est fixée à un certain nombre de colonnes. Je codifie également en dur les en-têtes, mais il a utilisé les noms de variables de son tableau pour générer les en-têtes de table. Je ne sais pas si ces différences pourraient empêcher les choses de fonctionner.

<section class="score-cards">
    <app-score-cards></app-score-cards>
</section>
<section class="live-updates-wrapper">
    <div class="table-wrapper">
        <table class="stock-updates">
            <thead>
                <tr>
                    <th class="ticker-fixed">Ticker</th>
                    <th><a (click)="sortedColumn = $any($event.target).textContent">Ask Price</a></th>
                    <th><a (click)="sortedColumn = $any($event.target).textContent">Tax Value</a></th>
                    <th><a (click)="sortedColumn = $any($event.target).textContent">Est. Value</a></th>
                    <th><a (click)="sortedColumn = $any($event.target).textContent">Location</a></th>
                </tr>
            </thead>
            <tbody>
                <tr *ngFor="let s of stocks$ | async | sort : sortedColumn">
                    <td class="ticker-fixed">
                        <a target="_blank" href="https://robinhood.com/stocks/{{ s.TICKER }}">{{ s.TICKER }}</a>
                        <span class="sp500">{{ s.sp500_flag }}S&P</span>
                    </td>
                    <td>{{ s.CLOSE }}</td>
                    <td>{{ s.tax_diff }}</td>
                    <td>{{ s.MarketCap }}</td>
                    <td>{{ s.Sector }}</td>
                </tr>
            </tbody>
        </table>
    </div>
</section>

J'obtenais l'erreur suivante ci-dessous, mais j'ai pu la corriger en injectant le code suivant dans mon fichier pipe: list = !!list ? list : [];

Il n'y a maintenant aucune erreur, mais le tri ne fonctionne pas comme prévu. Lorsque je clique sur l'en-tête du tableau, rien ne se passe. Comment puis-je réparer cela?

Réponses

2 bryan60 Aug 28 2020 at 19:17

oubliez la pipe. le tri via un tube est une mauvaise pratique, conduit à un code bogué ou à de mauvaises performances.

Utilisez plutôt des observables.

Commencez par modifier les boutons d'en-tête de votre modèle pour appeler une fonction, et assurez-vous également que vous fournissez les noms de propriété réels que vous souhaitez trier, plutôt que le contenu de l'en-tête:

<th><a (click)="sortOn('CLOSE')">Ask Price</a></th>
<th><a (click)="sortOn('tax_diff')">Tax Value</a></th>
<th><a (click)="sortOn('MarketCap')">Est. Value</a></th>
<th><a (click)="sortOn('Sector')">Location</a></th>

puis, sortez votre fonction de tri et importez dans votre composant:

  export function sortByColumn(list: any[] | undefined, column:string, direction = 'desc'): any[] {
      let sortedArray = (list || []).sort((a,b)=>{
        if(a[column] > b[column]){
          return (direction === 'desc') ? 1 : -1;
        }
        if(a[column] < b[column]){
          return (direction === 'desc') ? -1 : 1;
        }
        return 0;
      })
    return sortedArray;
  }

puis réparez votre composant:

// rx imports
import { combineLatest, BehaviorSubject } from 'rxjs';
import { map, scan } from 'rxjs/operators';

...

export class LiveUpdatesComponent implements OnInit{
  stocks$: Observable<any[]>; // make this a behavior subject instead sortedColumn$ = new BehaviorSubject<string>('');
  
  // the scan operator will let you keep track of the sort direction
  sortDirection$ = this.sortedColumn$.pipe(
    scan<string, {col: string, dir: string}>((sort, val) => {
      return sort.col === val
        ? { col: val, dir: sort.dir === 'desc' ? 'asc' : 'desc' }
        : { col: val, dir: 'desc' }
    }, {dir: 'desc', col: ''})
  )

  constructor(private updatesService: LiveUpdatesService, public nav: NavbarService) {
    // combine observables, use map operator to sort
    this.stocks$ = combineLatest(this.updatesService.getStocks(), this.sortDirection$).pipe(
      map(([list, sort]) => !sort.col ? list : sortByColumn(list, sort.col, sort.dir))
    );
  }

  // add this function to trigger subject
  sortOn(column: string) {
    this.sortedColumn$.next(column);
  }

  ngOnInit() {
    this.nav.show();
  }
}

enfin, corrigez votre ngFor:

<tr *ngFor="let s of stocks$ | async">

de cette façon, vous ne comptez pas sur la magie ou la détection de changement. vous déclenchez votre tri quand il doit se déclencher via des observables

2 Ondie Aug 26 2020 at 16:01

Je pense que vos valeurs ne sont pas transmises dans le tube:

Peux-tu essayer:

<tr *ngFor="let s of ((stocks$ | async) | sort : sortedColumn)">
1 karthicvel Sep 02 2020 at 12:02

L'appel Asyn ici avant d'affecter la this.stocks$table de valeurs chargera le tube sera appelé

 constructor(private updatesService: LiveUpdatesService, public nav: NavbarService) {
    this.stocks$ = this.updatesService.getStocks();
  }

Modèle

 <tbody *ngIf="stocks$"> <tr *ngFor="let s of stocks$ | sort : sortedColumn">
          ....
        </tr>
  </tbody>