Bản trình diễn sắp xếp bảng mat-xa không hoạt động


105

Tôi đang cố gắng để mat-tablesắp xếp hoạt động cục bộ và trong khi tôi có thể khiến dữ liệu hiển thị như mong đợi, việc nhấp vào hàng tiêu đề không thực hiện việc sắp xếp như trên các ví dụ trực tuyến (không có gì xảy ra cả). Tôi đang cố gắng làm cho bản demo này hoạt động cục bộ: https://material.angular.io/components/sort/overview https://plnkr.co/edit/XF5VxOSEBxMTd9Yb3ZLA?p=preview

Tôi đã tạo một dự án mới với Angular CLI, sau đó làm theo các bước sau: https://material.angular.io/guide/getting-started

Đây là các tệp cục bộ của tôi:

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { MatSort, MatTableModule } from '@angular/material';

import { AppComponent } from './app.component';
import { TableSortingExample } from './table-sorting-example';

@NgModule({
  declarations: [
    AppComponent,
    TableSortingExample,
    MatSort
  ],
  imports: [
    BrowserModule,
    MatTableModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';
}

app.component.html

<div style="text-align:center">
  <h1>
    Welcome to {{title}}!
  </h1>
  <table-sorting-example></table-sorting-example>
</div>

table-sorting-example.html

<div class="example-container mat-elevation-z8">
  <mat-table #table [dataSource]="dataSource" matSort>

    <!--- Note that these columns can be defined in any order.
          The actual rendered columns are set as a property on the row definition" -->

    <!-- ID Column -->
    <ng-container matColumnDef="userId">
      <mat-header-cell *matHeaderCellDef mat-sort-header> ID </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.id}} </mat-cell>
    </ng-container>

    <!-- Progress Column -->
    <ng-container matColumnDef="progress">
      <mat-header-cell *matHeaderCellDef mat-sort-header> Progress </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.progress}}% </mat-cell>
    </ng-container>

    <!-- Name Column -->
    <ng-container matColumnDef="userName">
      <mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.name}} </mat-cell>
    </ng-container>

    <!-- Color Column -->
    <ng-container matColumnDef="color">
      <mat-header-cell *matHeaderCellDef mat-sort-header> Color </mat-header-cell>
      <mat-cell *matCellDef="let row" [style.color]="row.color"> {{row.color}} </mat-cell>
    </ng-container>

    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
    <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
  </mat-table>
</div>


<!-- Copyright 2017 Google Inc. All Rights Reserved.
    Use of this source code is governed by an MIT-style license that
    can be found in the LICENSE file at http://angular.io/license -->

table-sorting-example.ts

import {Component, ViewChild} from '@angular/core';
import {DataSource} from '@angular/cdk/collections';
import {MatSort} from '@angular/material';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/observable/merge';
import 'rxjs/add/operator/map';

/**
 * @title Table with sorting
 */
@Component({
  selector: 'table-sorting-example',
  styleUrls: ['table-sorting-example.css'],
  templateUrl: 'table-sorting-example.html',
})
export class TableSortingExample {
  displayedColumns = ['userId', 'userName', 'progress', 'color'];
  exampleDatabase = new ExampleDatabase();
  dataSource: ExampleDataSource | null;

  @ViewChild(MatSort) sort: MatSort;

  ngOnInit() {
    this.dataSource = new ExampleDataSource(this.exampleDatabase, this.sort);
  }
}

/** Constants used to fill up our data base. */
const COLORS = ['maroon', 'red', 'orange', 'yellow', 'olive', 'green', 'purple',
  'fuchsia', 'lime', 'teal', 'aqua', 'blue', 'navy', 'black', 'gray'];
const NAMES = ['Maia', 'Asher', 'Olivia', 'Atticus', 'Amelia', 'Jack',
  'Charlotte', 'Theodore', 'Isla', 'Oliver', 'Isabella', 'Jasper',
  'Cora', 'Levi', 'Violet', 'Arthur', 'Mia', 'Thomas', 'Elizabeth'];

export interface UserData {
  id: string;
  name: string;
  progress: string;
  color: string;
}

/** An example database that the data source uses to retrieve data for the table. */
export class ExampleDatabase {
  /** Stream that emits whenever the data has been modified. */
  dataChange: BehaviorSubject<UserData[]> = new BehaviorSubject<UserData[]>([]);
  get data(): UserData[] { return this.dataChange.value; }

  constructor() {
    // Fill up the database with 100 users.
    for (let i = 0; i < 100; i++) { this.addUser(); }
  }

  /** Adds a new user to the database. */
  addUser() {
    const copiedData = this.data.slice();
    copiedData.push(this.createNewUser());
    this.dataChange.next(copiedData);
  }

  /** Builds and returns a new User. */
  private createNewUser() {
    const name =
      NAMES[Math.round(Math.random() * (NAMES.length - 1))] + ' ' +
      NAMES[Math.round(Math.random() * (NAMES.length - 1))].charAt(0) + '.';

    return {
      id: (this.data.length + 1).toString(),
      name: name,
      progress: Math.round(Math.random() * 100).toString(),
      color: COLORS[Math.round(Math.random() * (COLORS.length - 1))]
    };
  }
}

/**
 * Data source to provide what data should be rendered in the table. Note that the data source
 * can retrieve its data in any way. In this case, the data source is provided a reference
 * to a common data base, ExampleDatabase. It is not the data source's responsibility to manage
 * the underlying data. Instead, it only needs to take the data and send the table exactly what
 * should be rendered.
 */
export class ExampleDataSource extends DataSource<any> {
  constructor(private _exampleDatabase: ExampleDatabase, private _sort: MatSort) {
    super();
  }

  /** Connect function called by the table to retrieve one stream containing the data to render. */
  connect(): Observable<UserData[]> {
    const displayDataChanges = [
      this._exampleDatabase.dataChange,
      this._sort.sortChange,
    ];

    return Observable.merge(...displayDataChanges).map(() => {
      return this.getSortedData();
    });
  }

  disconnect() {}

  /** Returns a sorted copy of the database data. */
  getSortedData(): UserData[] {
    const data = this._exampleDatabase.data.slice();
    if (!this._sort.active || this._sort.direction == '') { return data; }

    return data.sort((a, b) => {
      let propertyA: number|string = '';
      let propertyB: number|string = '';

      switch (this._sort.active) {
        case 'userId': [propertyA, propertyB] = [a.id, b.id]; break;
        case 'userName': [propertyA, propertyB] = [a.name, b.name]; break;
        case 'progress': [propertyA, propertyB] = [a.progress, b.progress]; break;
        case 'color': [propertyA, propertyB] = [a.color, b.color]; break;
      }

      let valueA = isNaN(+propertyA) ? propertyA : +propertyA;
      let valueB = isNaN(+propertyB) ? propertyB : +propertyB;

      return (valueA < valueB ? -1 : 1) * (this._sort.direction == 'asc' ? 1 : -1);
    });
  }
}


/**  Copyright 2017 Google Inc. All Rights Reserved.
 Use of this source code is governed by an MIT-style license that
 can be found in the LICENSE file at http://angular.io/license */

Có ai biết tại sao nó sẽ hiển thị giống như bảng trực tuyến nhưng thiếu chức năng sắp xếp không?


Tôi sẽ gỡ lỗi ứng dụng trước. Có lỗi gì không? chạy ng test --sm=falsevà xem những gì xuất hiện.
k.vincent

Nó đang hoạt động đối với tôi mà không có sắp xếp @ViewChild (MatSort): MatSort; Có lý do gì không?
user123456

Câu trả lời:


197

Đối với bất kỳ ai khác có thể gặp sự cố này: Vấn đề là tôi đã không đọc tài liệu tham khảo API một cách chính xác trên trang web vật liệu góc cạnh, phần cho biết tôi phải nhập MatSortModule. Sau khi tôi thay đổi danh sách nhập của mình trong app.module.ts thành

imports: [
    BrowserModule,
    MatTableModule,
    MatSortModule
  ],

nó hoạt động tốt


45
không có đề cập đến mô-đun này trong tài liệu. material.angular.io/components/table/overview#sorting Tôi cũng đã lãng phí một giờ cho việc này.
Sonic Soul

8
điều này là tốt, trong văn bản tiêu đề có thể nhấp vào và biểu tượng cũng ở đó nhưng vẫn phân loại không hoạt động.
SPnL

2
Kiểm tra xem BrowserAnimationsModulecó được nhập trong app.module.ts hay không
Augustas,

2
Tôi có thể nói chúng là SOB không? Tôi đã dành 1 giờ để tìm hiểu lý do tại sao ViewChild của tôi không hoạt động. Họ không thể nhập / xuất MatSortModule này từ MatTableModule ??
Sampgun

7
Tôi đã nhập MatSortModuleBrowserAnimationsModulevà tôi đã đảm bảo rằng giá trị matColumnDef khớp với tên thuộc tính, nhưng tôi vẫn không thể lấy nó để làm bất cứ điều gì.
Trevor

131

Tôi đã gặp sự cố rằng chức năng sắp xếp đang hoạt động nhưng nó không sắp xếp đúng cách. Tôi nhận ra rằng matColumnDefphải có cùng tên tài sản của tôi class / interfacemà tôi đang tham chiếu matCellDef.

Theo tài liệu Angular Material :

Theo mặc định, MatTableDataSource sắp xếp với giả định rằng tên của cột được sắp xếp khớp với tên thuộc tính dữ liệu mà cột đó hiển thị.

Ví dụ như:

<ng-container matColumnDef="name"> 
    <mat-header-cell *matHeaderCellDef mat-sort-header> NAME </mat-header-cell>
    <mat-cell *matCellDef="let row"> {{row.name}} </mat-cell>
</ng-container>

Các nametrong matColumnDefchỉ thị phải là giống như nameđược sử dụng trong <mat-cell>thành phần.


1
Bạn đang tham khảo điều gì trong ví dụ của bạn? Sẽ rất hữu ích khi xem giao diện của bạn để so sánh.
isherwood

1
Tôi đang sử dụng "Id" làm tên của cột trong khi thực thể có "id". Sự khác biệt về trường hợp đã làm cho nó không chạy (do lỗi cấu trúc lại) .. Bây giờ nó đã được giải quyết. Cảm ơn
NitinSingh

2
Cảm ơn bạn, nó rất hữu ích.
Bohao LI

2
@NitinSingh, điều gì sẽ xảy ra nếu bạn cần gọi một hàm trên element, như thế này `{{row.getName ()}} '
codentary

1
Tôi hoàn toàn nợ bạn một ly bia vì tôi đã bị mắc kẹt với vấn đề này trong một thời gian và nhận xét này đã khắc phục sự cố của tôi.
noel

99

Nếu bảng bên trong * ngIf, nó sẽ không hoạt động. Nó sẽ hoạt động nếu nó được thay đổi thành [hidden]


33
!!! BẠN LƯU NGÀY CỦA TÔI !!! Sử dụng thay vì <div *ngIf="xxx"> các<div [hidden]="!xxx">
Đánh dấu

1
Có thể xác nhận, điều này cũng làm việc cho tôi. Cảm ơn zerg!
clo5ure

1
Cảm ơn bạn rất nhiều, điều này đã làm tôi mất rất nhiều thời gian !!
themightylc

1
Hoặc chỉ cần thiết lập nguồn dữ liệu trong ngAfterViewInit thay vì ngOnInit
user3666653

1
Đây là vấn đề "ẩn" nhất có thể xảy ra, cảm ơn vì giải pháp! tài liệu có thể đã cảnh báo về điều này
Raycherr

35

Tên matColumnDef và tên giá trị thực * matCellDef phải giống nhau

Thí dụ:

<ng-container matColumnDef="oppNo">
    <th mat-header-cell *matHeaderCellDef mat-sort-header>Opportunity Number</th>
    <td mat-cell *matCellDef="let element">{{element.oppNo}}</td>
</ng-container>

Trong trường hợp của tôi, oppNo giống với tên matColumnDef và tên * matCellDef và việc sắp xếp hoạt động tốt.


Hấp dẫn. Đó cũng là trường hợp của tôi. Nhưng, bạn có biết lý do thực sự đằng sau điều này hay đó thực sự là một số loại "lỗi"?
ReturnTable

22

Thêm sắp xếp trong khối thời gian chờ phù hợp với tôi,

dataSource = new MatTableDataSource(this.articleService.getAllArticles());
setTimeout(() => {
  this.tableDataSource.sort = this.sort;
  this.tableDataSource.paginator = this.paginator;
});

Nếu bạn không muốn sử dụng các móc lifeecykle.


1
hack ngu ngốc nhưng nó hoạt động, bất kỳ ý tưởng tại sao nó không hoạt động mà không có thời gian chờ?
Ruben

Tôi đã dành quá nhiều thời gian để thử mọi thứ khác, nghĩ rằng tôi sẽ mất trí. Làm việc như người ở!
willpnw

4
Thực sự là một cách làm không tốt. Nó hoạt động vì bạn đang để một khoảng thời gian trôi qua sau khi khởi tạo thành phần để dataSource được tạo, sau đó bạn thêm sắp xếp và phân trang. Cách tốt nhất là di chuyển buidling datSource trong ngOnInit sau đó di chuyển các nhiệm vụ sắp xếp và phân trang trong AfterViewInit. Đó là những gì các móc Vòng đời tồn tại.
Selam Getachew

20

Tôi cũng nhấn vấn đề này. Vì bạn cần phải đợi con được định nghĩa, bạn phải triển khai và sử dụng AfterViewInit, không phải onInit.

  ngAfterViewInit (){
    this.dataSource.sort = this.sort;
  }

Tuyệt vời ! Cảm ơn
Shashank Vivek

Tôi đang sử dụng một bảng có sắp xếp, lọc và phân trang. Bạn có bất kỳ manh mối nào tại sao chỉ phân loại phải được xác định trong ngAfterViewInitkhông? Phần còn lại đang làm việc từ ngOnInit. Nó chỉ để cố gắng hiểu, nó được sửa chữa nhờ bạn
Nicolas M.

14

Tôi đã dành hàng giờ cho vấn đề này. Sau khi đọc qua một số chủ đề, đây là các bước tôi đã làm.

  1. Như @avern đã đề cập , bạn cần nhập MatSortModule.
  2. Đảm bảo rằng bạn KHÔNG đặt bảng trong một *ngIf. Thay đổi nó thành [hidden]như @zerg khuyến cáo . (Tôi không hiểu tại sao)

Hi vọng điêu nay co ich.


Nó đã lãng phí ngày của tôi để tìm ra vấn đề và ngu ngốc không hiển thị bất kỳ lỗi nào.
surekha shelake

11

Giải pháp của tôi là sửa một số thứ (về cơ bản là hợp nhất hầu hết các giải pháp trong trang này).

Những điều cần kiểm tra:

  1. BrowserModule, MatTableModule, MatSortModule Các mô-đun phải được nhập vào tệp mô-đun gốc.
  2. Đảm bảo đã sử dụng MatTableDatasourcelớp và chuyển mảng dữ liệu của bạn vào đó dưới dạng tham số
  3. Đảm bảo rằng bảng của bạn không được lồng trong một *ngIf=....chỉ thị. Sử dụng các phép toán điều kiện khác để thay thế (vẫn không hiểu tại sao).

3

Đối với tôi, việc thay thế * ngIf bằng thuộc tính [hidden] cho thẻ mat-table đã hoạt động. Làm cách nào để đăng cái này dưới dạng lỗi lên cộng đồng Angular Material?


3

Tôi đã sửa lỗi này trong kịch bản của mình bằng cách đặt tên dữ liệu bảng có cùng tên là * matColumnDef Ví dụ:

<!-- Name Column -->
<ng-container matColumnDef="name">
  <mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell>
  <mat-cell *matCellDef="let row"> {{row.name}} </mat-cell>
</ng-container>

Thay thế

<!-- Name Column -->
    <ng-container matColumnDef="userName">
      <mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell>
      <mat-cell *matCellDef="let row"> {{row.name}} </mat-cell>
    </ng-container>

3

Có 2 vấn đề đối với tôi.

  1. Tên matColumnDef và matCellDef -> khác nhau
  2. Tôi đã nhận được dữ liệu từ dịch vụ. Sắp xếp ngOnInit không hoạt động. Thay thế bằng

    ngAfterViewInit () {this.dataSource.sort = this.sort; }


2

Tôi tìm thấy blog cũ này đã giúp tôi hoạt động: https://www.jeffryhouser.com/index.cfm/2018/10/23/Five-Reasons-My-ngMaterial-Table-wont-sort

  1. Đảm bảo nhập MatSortModule
  2. Chỉ định matSorttiêu đề
  3. Đảm bảo gói nguồn dữ liệu của bạn trong MatTableDataSource
    • Đây là một trong những giúp tôi sắp xếp nó ra (lấy nó ra? Sắp xếp nó ra). Trong mẫu, tôi đã đề cập trực tiếp đến mảng ( <table mat-table [dataSource]="this.products" matSort>) nhưng đáng lẽ tôi nên sử dụng đối tượng nguồn dữ liệu mà tôi đã khởi tạo trong mã ( <table mat-table [dataSource]="this.dataSource" matSort>). Nguồn dữ liệu được khởi tạo nhưdataSource = new MatTableDataSource(this.products)
  4. Cho nguồn dữ liệu biết về cách sắp xếp của bạn, trong ngOnInit/ngAfterViewInit
  5. Viết phân loại của riêng bạn, nếu bạn không muốn sử dụng MatTableDataSource

1

Nếu bảng của bạn nằm trong * ngIf và bạn nghĩ rằng nó có liên quan gì đó đến việc nó không sắp xếp được bảng của bạn, thì việc chỉ định sortingDataAccessorhàm của riêng bạn có thể giải quyết vấn đề như tôi đã làm. Tôi có bảng của mình bên trong một vài * ngIfs và lấy nó ra khỏi những * ngIfs đó không có ý nghĩa:

`ngAfterViewInit(): void {
        this.matchesDataSource.sort = this.sort;
        this.matchesDataSource.sortingDataAccessor = previewMatchSortingFn;
    }`

`export function previewMatchSortingFn(item: Match, header: string): string | number {
    switch (header) {
        case 'home':
            return item.homeTeam.name;
        case 'away':
            return item.awayTeam.name;
        case 'date':
            if (item.dateTime) {
                // this will return the number representation of the date
                return item.dateTime.valueOf();
            }
            return;
        default:
            break;
    }
}`

1

Một trong những lý do MatSort có thể không hoạt động là khi nó được thêm vào dataSource (tức là this.dataSource.sort = this.sort) trước khi nó được định nghĩa. Có thể có nhiều lý do cho điều này:

  1. nếu bạn thêm sắp xếp trong ngOnInit. Tại thời điểm này, mẫu vẫn chưa được hiển thị, vì vậy MatSort mà bạn nhận @ViewChild(MatSort, { static: true }) sort: MatSort;được không được xác định và có thể hiểu được sẽ không làm được gì cả. Giải pháp cho vấn đề này là chuyển this.dataSource.sort = sortsang ngAfterViewInit. Khi ngAfterViewInit được gọi, thành phần của bạn được hiển thị và MatSort sẽ được định nghĩa.

  2. khi bạn sử dụng * ngIf là mẫu của bạn trên phần tử bảng của bạn hoặc một mẫu nếu đó là các phần tử mẹ và * ngIf này khiến bảng của bạn không được hiển thị tại thời điểm bạn cố gắng đặt MatSort. Ví dụ: nếu bạn có *ngIf="dataSource.data.length > 0"phần tử bảng của mình (chỉ hiển thị phần tử đó nếu có dữ liệu) và bạn đặt this.dataSource.sort = this.sortngay sau khi đặt this.dataSource.datavới dữ liệu của mình. Chế độ xem thành phần sẽ chưa được hiển thị, vì vậy MatSort vẫn sẽ không được xác định.

Để MatSort hoạt động và vẫn hiển thị có điều kiện bảng của bạn, bạn có thể quyết định thay thế *ngIfbằng [hidden]như đã nêu trong nhiều câu trả lời khác. Tuy nhiên, nếu bạn muốn giữ lại câu lệnh * ngIf, bạn có thể sử dụng giải pháp sau. Giải pháp này hoạt động cho Angular 9, tôi chưa thử nghiệm nó trên các phiên bản trước nên tôi không chắc liệu nó có hoạt động ở đó hay không.

Tôi tìm thấy giải pháp này ở đây: https://github.com/angular/components/issues/10205

Thay vì đặt:

@ViewChild(MatSort) sort: MatSort;

sử dụng một setter cho matSort. Trình cài đặt này sẽ kích hoạt khi matSort trong chế độ xem của bạn thay đổi (nghĩa là được xác định lần đầu tiên), nó sẽ không kích hoạt khi bạn thay đổi sắp xếp bằng cách nhấp vào các mũi tên. Nó sẽ trông như thế này:

@ViewChild(MatSort) set matSort(sort: MatSort) {
    this.dataSource.sort = sort;
}

Nếu bạn có các chức năng khác (theo chương trình) thay đổi việc sắp xếp, tôi không chắc liệu nó có kích hoạt lại hay không, tôi chưa thử nghiệm điều này. Nếu bạn không thể đảm bảo rằng nó chỉ đặt sắp xếp nếu sắp xếp không được xác định, bạn có thể làm như sau:

@ViewChild(MatSort) set matSort(sort: MatSort) {
    if (!this.dataSource.sort) {
        this.dataSource.sort = sort;
    }
}

0

Xem bạn có bất kỳ lỗi javascript nào trong bảng điều khiển không. Nó có thể là một số điều khác không thành công trước khi sắp xếp của bạn được khởi tạo.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.