【问题标题】:Async pipe on MatTable datasource doesn't sort, table contents update fineMatTable 数据源上的异步管道未排序,表格内容更新正常
【发布时间】:2022-08-11 01:17:07
【问题描述】:

我有一个 MatTable 可以在基础数据更改/添加/删除时正确加载和刷新,我遇到的唯一问题是单击其中一个标题时它没有排序,出现小箭头图标但没有变化。我在 html 中对 Observable 使用条件,并在 ngOnInit() 中设置了排序,但我尝试过的所有操作都不会触发任何排序。我找不到任何同时执行异步管道和 matSort 的示例,其中有很多示例。任何见解将不胜感激。

html:

   <mat-card-header layout=\"row\">
      <mat-card-title style=\"margin-bottom: 4vh\">
         <span>{{ msg }}</span>
      </mat-card-title>
   </mat-card-header>
   <mat-card-content>
      <table
      *ngIf=\"expenseDataSource$ | async as expenses\"
      mat-table
      [dataSource]=\"expenses\"
      matSort
      matSortDisableClear
      #expTbSort=\"matSort\"
      class=\"mat-elevation-z8\"
      >
      <ng-container matColumnDef=\"id\">
         <th mat-header-cell *matHeaderCellDef mat-sort-header>
            <div class=\"center-header\" style=\"width: 50%\">Expense</div>
         </th>
         <td mat-cell *matCellDef=\"let element\">{{ element.id }}</td>
      </ng-container>
      <!-- Date Column -->
      <ng-container matColumnDef=\"dateincurred\">
         <th
            mat-header-cell
            *matHeaderCellDef
            mat-sort-header
            >
            <div class=\"center-header\">Expense Date</div>
         </th>
         <td mat-cell *matCellDef=\"let element\">{{ element.dateincurred }}</td>
      </ng-container>
      <!-- Employee Id Column  -->
      <ng-container matColumnDef=\"employeeid\">
         <th mat-header-cell *matHeaderCellDef mat-sort-header>
            <div class=\"center-header\">Employee</div>
         </th>
         <td mat-cell *matCellDef=\"let element\">{{ element.employeeid }}</td>
      </ng-container>
      <tr mat-header-row *matHeaderRowDef=\"displayedColumns; sticky: true\"></tr>
      <tr
      mat-row
      *matRowDef=\"let row; columns: displayedColumns\"
      (click)=\"select(row)\"
      ></tr>
      </table>
      <div class=\"padtop15\">
         <mat-icon
            (click)=\"newExpense()\"
            matTooltip=\"Add New Expense\"
            class=\"addicon\"
            color=\"primary\"
            >
            control_point
         </mat-icon>
      </div>
   </mat-card-content>
</mat-card>
<mat-card *ngIf=\"!hideEditForm\">
   <mat-card-header layout=\"row\">
      <mat-card-title
         ><span>{{ msg }}</span></mat-card-title
         >
   </mat-card-header>
   <mat-card-content>
      <app-expense-detail
      [selectedExpense]=\"expense\"
      [employees]=\"employees$ | async\"
      (cancelled)=\"cancel(\'cancelled\')\"
      (saved)=\"save($event)\"
      (deleted)=\"delete($event)\"
      >
      </app-expense-detail>
   </mat-card-content>
</mat-card>

ts:

import { Component, OnInit, ViewChild } from \'@angular/core\';
import { MatTableDataSource } from \'@angular/material/table\';
import { MatSort, Sort } from \'@angular/material/sort\';
import { Expense } from \'@app/expense/expense\';
import { Employee } from \'@app/employee/employee\';
import { EmployeeService } from \'@app/employee/employeev3.service\';
import { ExpenseService } from \'@app/expense/expense.service\';
import { Observable } from \'rxjs\';
import { catchError, tap, map } from \'rxjs/operators\';

@Component({
  selector: \'app-expense\',
  templateUrl: \'expense-home.component.html\',
})
export class ExpenseHomeComponent implements OnInit {
  employees$?: Observable<Employee[]>;
  expenses: Expense[];
  expenses$?: Observable<Expense[]>;
  expenseDataSource$: Observable<MatTableDataSource<Expense>> | undefined;
  expense: Expense;
  hideEditForm: boolean;
  initialLoad: boolean;
  msg: string;
  todo: string;
  url: string;
  size: number = 0;
  displayedColumns: string[] = [\'id\', \'dateincurred\', \'employeeid\'];

  @ViewChild(\'expTbSort\') expTbSort = new MatSort();

  constructor(
    private employeeService: EmployeeService,
    private expenseService: ExpenseService
  ) {
    this.hideEditForm = true;
    this.initialLoad = true;
    this.expenses = [];
    this.expense = {
      id: 0,
      employeeid: 0,
      categoryid: \'\',
      description: \'\',
      amount: 0.0,
      dateincurred: \'\',
      receipt: false,
      receiptscan: \'\',
    };
    this.msg = \'\';
    this.todo = \'\';
    this.url = \'\';
  } // constructor

  ngOnInit(): void {
    this.msg = \'loading expenses from server...\';
    this.expenses$ = this.expenseService.get();
    this.expenseDataSource$ = this.expenses$.pipe(
      map((expenses) => {
        const dataSource = new MatTableDataSource<Expense>(expenses);
        // dataSource.data = expenses;
        dataSource.sort = this.expTbSort;
        return dataSource;
      }),
      tap(() => {
        this.employees$ = this.employeeService.get();
        if (this.initialLoad === true) {
          this.msg = \'expenses and employees loaded!\';
          this.initialLoad = false;
        }
      })
    );
  }

  select(selectedExpense: Expense): void {
    this.todo = \'update\';
    this.expense = selectedExpense;
    this.msg = `Expense ${selectedExpense.id} selected`;
    this.hideEditForm = !this.hideEditForm;
  } // select

  /**
   * cancelled - event handler for cancel button
   */
  cancel(msg?: string): void {
    this.hideEditForm = !this.hideEditForm;
    this.msg = \'operation cancelled\';
  } // cancel

  /**
   * update - send changed update to service update local array
   */
  update(selectedExpense: Expense): void {
    this.expenseService.update(selectedExpense).subscribe({
      // Create observer object
      next: (exp: Expense) => (this.msg = `Expense ${exp.id} updated!`),
      error: (err: Error) => (this.msg = `Update failed! - ${err.message}`),
      complete: () => {
        this.hideEditForm = !this.hideEditForm;
      },
    });
  } // update

  /**
   * save - determine whether we\'re doing and add or an update
   */
  save(expense: Expense): void {
    expense.id ? this.update(expense) : this.add(expense);
  } // save

  /**
   * add - send expense to service, receive newid back
   */
  add(newExpense: Expense): void {
    this.msg = \'Adding expense...\';
    newExpense.id = 0;
    this.expenseService.add(newExpense).subscribe({
      // Create observer object
      next: (exp: Expense) => {
        this.msg = `Expense ${exp.id} added!`;
      },
      error: (err: Error) => (this.msg = `Expense not added! - ${err.message}`),
      complete: () => {
        this.hideEditForm = !this.hideEditForm;
      },
    });
  } // add

  /**
   * newExpense - create new expense instance
   */
  newExpense(): void {
    this.expense = {
      id: 0,
      employeeid: 0,
      categoryid: \'\',
      description: \'\',
      amount: 0.0,
      dateincurred: \'\',
      receipt: false,
      receiptscan: \'\',
    };
    this.msg = \'New expense\';
    this.hideEditForm = !this.hideEditForm;
  } // newExpense

  /**
   * delete - send expense id to service for deletion
   */
  delete(selectedExpense: Expense): void {
    this.expenseService.delete(selectedExpense.id).subscribe({
      // Create observer object
      next: (numOfExpensesDeleted: number) => {
        numOfExpensesDeleted === 1
          ? (this.msg = `Expense ${selectedExpense.id} deleted!`)
          : (this.msg = `Expense ${selectedExpense.id} not deleted!`);
      },
      error: (err: Error) => (this.msg = `Delete failed! - ${err.message}`),
      complete: () => {
        this.hideEditForm = !this.hideEditForm;
      },
    });
  }
} // ExpenseHomeComponent

    标签: angular sorting asynchronous angular-material angular2-observables


    【解决方案1】:

    通过添加自定义排序方法并在表格上添加 matSortChange 属性,我得到了排序功能

    【讨论】:

      【解决方案2】:

      我自己一直在处理这个问题。我认为问题出在您的行:dataSource.sort = this.expTbSort; 在视图呈现之前正在运行。

      @ViewChild('expTbSort') expTbSort = new MatSort(); 行表示变量expTbSort 将使用从视图中获取的数据填充,因此视图必须在分配dataSource.sort 之前渲染。

      您实现异步管道的方式可确保在 ngOnInit 运行并定义 this.expenseDataSource$ 之前视图不会呈现。

      我不确定您的案例的理想解决方案,但希望这种观点对您有所帮助。就我而言,我的表填充了来自 API 调用的响应,因此我在 .subscribe() 回调中定义了 dataSource.sort。我不需要像 Angular Material 文档中的示例那样使用 ngAfterViewInit 生命周期钩子。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-10-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多