在“总计”列中不起作用的角度垫表中排序

时间:2020-08-03 05:24:14

标签: angular typescript sorting ecmascript-6 reduce

我的垫子表工作正常,我的所有列都在排序,除了我的最后一列使用reduce来计算其他列的总和值。

我有点卡在这个问题上,尽管首先可能是归约方法在OnInit生命周期之后发生,但是即使我在this.dataSource.data = this.data中声明ngAfterViewInit也不起作用。 / p>

我的HTML模板:

<div [ngClass]="{'hidden': !hasData()}">
  <div class="subcollection-name">{{subCollection.name}}</div>
  <div class="table-container">
    <table
      matSort
      mat-table
      class="items-table"
      [dataSource]="dataSource"
    >
      <ng-container matColumnDef="coverUrl">
        <th mat-header-cell *matHeaderCellDef></th>
        <td mat-cell *matCellDef="let item">
          <img class="item-image" src="{{item.displayImage}}" onError="this.src='assets/images/no-image-available.png';">
        </td>
        <td mat-footer-cell *matFooterCellDef>
          {{ "collectionReportsSubcollectionTablesTotalRow" | translate }}
        <td>
      </ng-container>

      <ng-container matColumnDef="id">
        <th mat-header-cell *matHeaderCellDef mat-sort-header>
          {{ 'collectionRejectionReportRejectedItemTableHeaderId' | translate}}
        </th>
        <td mat-cell *matCellDef="let item">
          <a target="_blank" routerLink="/item/{{item.id}}" class="item-id-link">ID-{{ item.id }}</a>
        </td>
        <td mat-footer-cell *matFooterCellDef></td>
      </ng-container>

      <ng-container matColumnDef="name" sticky>
        <th mat-header-cell *matHeaderCellDef mat-sort-header>
          {{ 'collectionRejectionReportRejectedItemTableHeaderName' | translate}}
        </th>
        <td mat-cell *matCellDef="let item">{{ item | displayItemName }}</td>
        <td mat-footer-cell *matFooterCellDef></td>
      </ng-container>

      <ng-container *ngFor="let step of stepsName$ | async">
        <ng-container matColumnDef="{{step}}">
          <th mat-header-cell *matHeaderCellDef mat-sort-header>
            {{step}}
          </th>
          <td mat-cell *matCellDef="let item">{{ 'stepsReportAverageTimeSpentDaysUnit' | translate: { numberDays: getDataOfItemForStepName(item.id, step) } }}</td>
          <td mat-footer-cell *matFooterCellDef>{{ 'stepsReportAverageTimeSpentDaysUnit' | translate: { numberDays: getTotalDataOfStep(step) } }}</td>
        </ng-container>
      </ng-container>

      <ng-container matColumnDef="total" stickyEnd>
        <th mat-header-cell *matHeaderCellDef mat-sort-header>
          {{ "collectionReportsSubcollectionTablesTotalCollumn" | translate }}
        </th>
        <td mat-cell *matCellDef="let item">{{ 'stepsReportAverageTimeSpentDaysUnit' | translate:{ numberDays: getTotalDataOfItem(item.id) } }}</td>
        <td mat-footer-cell *matFooterCellDef>{{ 'stepsReportAverageTimeSpentDaysUnit' | translate:{ numberDays: getTotalDataOfAll() } }}</td>
      </ng-container>

      <tr mat-header-row *matHeaderRowDef="columns; sticky: true"></tr>
      <tr mat-row *matRowDef="let row; columns: columns;"></tr>
      <tr mat-footer-row *matFooterRowDef="columns"></tr>
    </table>
  </div>
  <mat-paginator [pageSizeOptions]="[5, 10, 25, 100]"></mat-paginator>
</div>

TypeScript文件

import { Observable, BehaviorSubject } from 'rxjs';
import { SubCollection } from 'model/item-tree/collection';
import { MatSort, MatPaginator, MatTableDataSource } from '@angular/material';
import { Component, ViewChild, Input, OnInit, ChangeDetectionStrategy, AfterViewInit, OnChanges } from '@angular/core';

@Component({
  selector: 'app-collection-steps-report-subcollection-table',
  templateUrl: './collection-steps-report-subcollection-table.component.html',
  styleUrls: ['./collection-steps-report-subcollection-table.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class CollectionStepsReportSubcollectionTableComponent implements OnInit {

  @ViewChild(MatSort, { static: true }) sort: MatSort;
  @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;

  @Input() data: any[];
  @Input() subCollection: SubCollection;
  @Input() filterBy$: Observable<string>;
  @Input() stepsName$: BehaviorSubject<string[]>;

  public columns: string[];
  public dataSource = new MatTableDataSource();

  public ngOnInit(): void {
    this.dataSource.filterPredicate = (data: any, filter: string): boolean => {
      if (filter === 'id') {
        return true;
      }
      const id = data['id'] as string;
      const name = data['name'] as string;
      const matchId = (id) ? id.trim().toLowerCase().indexOf(filter) !== -1 : true;
      const matchName = (name) ? name.trim().toLowerCase().indexOf(filter) !== -1 : true;
      return matchName || matchId;
    };
    this.dataSource.sort = this.sort;
    this.dataSource.paginator = this.paginator;
    this.filterBy$.subscribe(
      filter => {
        this.dataSource.filter = filter.trim().toLowerCase();

        if (this.dataSource.paginator) {
          this.dataSource.paginator.firstPage();
        }
      }
    );

    this.stepsName$.subscribe(
      sn => {
        this.columns = ['coverUrl', 'id', 'name', ...sn, 'total'];
      }
    );
    this.dataSource.data = this.data;
  }

  public hasData(): boolean {
    return Array.isArray(this.data) && this.data.length > 0;
  }

  public getTotalDataOfItem(itemId: string): number {
    const item = this.data.find(i => i.id === itemId);
    return this.stepsName$.getValue().reduce((acc, stepName) => {
      return acc += item[stepName];
    }, 0);
  }

  public getTotalDataOfAll(): number {
    return this.data.reduce(
      (acc1, item) => acc1 += this.stepsName$.getValue().reduce((acc2, stepName) => acc2 += item[stepName], 0)
    , 0);
  }

  public getDataOfItemForStepName(itemId: string, stepName: string): string {
    return this.data.find(i => i.id === itemId)[stepName];
  }

  public getTotalDataOfStep(step: string): number {
    return this.data.reduce((acc, item) => acc += item[step], 0);
  }
}

很高兴有任何提示或帮助澄清我的想法来解决这个问题:)谢谢!

1 个答案:

答案 0 :(得分:0)

经过一番尝试,我发现我的问题是'total'列不是'item'对象的一部分。

因此,我对数据实现了map方法,将getTotalDataOfItem函数的返回值分配给了ngOnInit内的新数据数组,并且效果很好!

由于我的商品现在具有“总计”列,因此我必须重构HTML模板以在item.total中呈现<td>,而不是返回getTotalDataOfItem(item.id)

要使其正常工作,只需将此代码添加到TS文件的ngOnInit

const dataWithTotal = this.data.map(
  value => {
    return {
      ...value, total: this.getTotalDataOfItem(value['id'])
    };
  }
);

然后像这样重构HTML文件

<td mat-cell *matCellDef="let item">{{ 'stepsReportAverageTimeSpentDaysUnit' | translate:{ numberDays: item.total } }}</td>

然后享受您的mat-table正确排序所有列的方法:)