Menyortir kolom tabel di Angular

Aug 26 2020

Saya mencoba membuat kolom tabel saya dapat diurutkan. Saya menemukan tutorial ini di sini:https://www.youtube.com/watch?v=UzRuerCoZ1E&t=715s

Menggunakan informasi itu, saya berakhir dengan yang berikut:

Pipa yang menangani penyortiran

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;
      }
    
    }

Inilah komponen yang membantu saya membuat tabel saya. Di sini saya mendefinisikan variabel sortColumn.

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();
  }
}

Ini file template saya. Seperti yang Anda lihat, saya telah memasang sortpipa saya ke loop saya, mengeluarkan baris tabel. Perlu dicatat bahwa cara saya merender tabel berbeda dari video. Misalnya, datanya disimpan dalam array, tetapi milik saya disimpan di Firebase. Dia merender tabelnya secara dinamis, tetapi tabel saya ditetapkan ke sejumlah kolom tertentu. Saya juga melakukan hardcode pada header, tetapi dia menggunakan nama variabel dari arraynya untuk menghasilkan header tabel. Saya tidak yakin apakah perbedaan ini dapat mencegah hal-hal bekerja.

<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>

Saya mendapatkan kesalahan berikut di bawah ini, tetapi dapat memperbaikinya dengan menyuntikkan kode berikut di file pipa saya: list = !!list ? list : [];

Sekarang tidak ada kesalahan, tetapi pengurutan tidak berfungsi seperti yang diharapkan. Saat saya mengklik header tabel, tidak ada yang terjadi. Bagaimana cara memperbaikinya?

Jawaban

2 bryan60 Aug 28 2020 at 19:17

lupakan pipanya. menyortir melalui pipa adalah praktik yang buruk, menyebabkan kode buggy atau kinerja buruk.

Gunakan observasi sebagai gantinya.

pertama-tama ubah tombol header template Anda untuk memanggil suatu fungsi, dan juga pastikan Anda memberi makan nama properti sebenarnya yang ingin Anda sortir, bukan konten header:

<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>

kemudian, tarik fungsi sortir Anda dan impor ke komponen Anda:

  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;
  }

lalu perbaiki komponen Anda:

// 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();
  }
}

terakhir, perbaiki ngFor:

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

dengan cara ini, Anda tidak mengandalkan sihir atau deteksi perubahan. Anda memicu penyortiran Anda saat perlu memicu melalui observasi

2 Ondie Aug 26 2020 at 16:01

Saya pikir nilai Anda tidak diteruskan ke dalam pipa:

Bisakah kamu mencoba:

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

Panggilan Asyn ke sana sebelum menetapkan this.stocks$tabel nilai akan memuat pipa akan dipanggil

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

Template

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