角度matSort不工作

时间:2017-10-17 09:22:24

标签: angular angular-material

我将matSort导入matTable时遇到了麻烦。

我正在为您提供我的代码:

dashboard.component.ts

import {Component, ViewChild} from '@angular/core';
import {UserService} from "../user.service";
import {DohvatMantisaService} from "../dohvat-mantisa.service";
import {Mantisi} from "../Mantisi";
import {Observable} from "rxjs/Observable";
import {DataSource} from "@angular/cdk/collections";
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/startWith';
import 'rxjs/add/observable/merge';
import {MatSort} from '@angular/material';
@Component({
  selector: 'app-dashboard',
  templateUrl: './dashboard.component.html',
  styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent{
  displayedColumns = ['projekt', 'manits', 'kategorija','ozbiljnost','datum_prijave','postavio','odjel','postavio','naziv','status','planirana_isporuka'];
  constructor(private user:UserService, private dohvatMantisa:DohvatMantisaService) {
  }
  dataSource: TableDataSource | null;
  mantisi: Mantisi[];
  name = this.user.getUsername();
  @ViewChild(MatSort) sort: MatSort;
  ngOnInit() {
    this.dataSource = new TableDataSource(this.dohvatMantisa,this.sort);
  }
}

export class TableDataSource extends DataSource<Mantisi>{
  constructor(private mantisiDS: DohvatMantisaService,private sort: MatSort){
    super();
  }
  connect(): Observable<Mantisi[]> {
    const displayDataChanges = [
      this.mantisiDS.dohvatiMantise(),
      this.sort.sortChange,
    ];

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

  getSortedData(): Mantisi[]{
    const data = this.mantisiDS.prikazMantisa().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 'projekt': [propertyA, propertyB] = [a.projekt, b.projekt]; break;
        case 'manits': [propertyA, propertyB] = [a.manits, b.manits]; break;
        case 'kategorija': [propertyA, propertyB] = [a.kategorija, b.kategorija]; break;
        case 'ozbiljnost': [propertyA, propertyB] = [a.ozbiljnost, b.ozbiljnost]; break;
        case 'datum_prijave': [propertyA, propertyB] = [a.datum_prijave, b.datum_prijave]; break;
        case 'postavio': [propertyA, propertyB] = [a.postavio, b.postavio]; break;
        case 'naziv': [propertyA, propertyB] = [a.naziv, b.naziv]; break;
        case 'status': [propertyA, propertyB] = [a.status, b.status]; break;
        case 'planirana_isporuka': [propertyA, propertyB] = [a.planirana_isporuka, b.planirana_isporuka]; break;
      }

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

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

这是我的服务: 的 dohvatMantisaService

import { Injectable } from '@angular/core';
import {Http, Response, RequestOptions, Headers} from "@angular/http";
import {Observable} from "rxjs/Observable";
import {Mantisi} from "./Mantisi";
import 'rxjs';
import 'rxjs/operator/map';
import 'rxjs/operator/do';

@Injectable()
export class DohvatMantisaService {
  constructor(public http:Http) { }
  result: Mantisi[];
  dohvatiMantise(): Observable<Mantisi[]>{
    return this.http.get('/mantis/getMantisReport').map(this.extractData);
  }
  private extractData(response: Response) {
    let body = response.json();
    return body || {};
  }

  prikazMantisa(): Mantisi[]{
    this.dohvatiMantise().subscribe(res => this.result = res);
    return this.result;
  }
}

我正在为您提供我的dashboard.component.html matSort行:

<mat-table #table [dataSource]="dataSource" class="example-table" matSort>

这里的主要问题是数据是从http请求加载和获取的,但我在控制台中遇到的错误是这样的:

  

无法读取未定义的属性'sortChange'       在TableDataSource.webpackJsonp ... / .. / .. / .. / .. / src / app / dashboard / dashboard.component.ts.TableDataSource.connect(dashboard.component.ts:36)       在MatTable.webpackJsonp ... / .. / .. / cdk / esm5 / table.es5.js.CdkTable._observeRenderChanges(table.es5.js:602)       在MatTable.webpackJsonp ... / .. / .. / cdk / esm5 / table.es5.js.CdkTable.ngAfterContentChecked(table.es5.js:522)

它告诉我 this.sort.sortChange 未定义。 我搜索了所有的互联网,但找不到合适的答案。希望你能帮助我。

10 个答案:

答案 0 :(得分:35)

如果使用“* ngIf”初始隐藏模板中的表容器,则视图字段将是未定义的。

答案 1 :(得分:35)

我遇到了这个问题,而我所要做的就是确保您正确引用matSort viewChild并确保在您的module.ts文件中添加了MatSortModule进口区。

如下所示: @NgModule({ imports: [ MatSortModule, MatTableModule, ] )}

答案 2 :(得分:12)

我找到了解决这个问题的方法。

主要问题是在数据到达之前呈现了表。我首先加载了数据并将其像源一样发送到dataSource构造函数。之后,问题就消失了。这就是async http.get和services。

谢谢你的帮助。

fetchData(id){
  this.fetch.getProcesses(id).subscribe(result => {
    this.processes = result;
    this.dataSource = new TableDataSource(this.processes);
    Observable.fromEvent(this.filter.nativeElement, 'keyup')
      .debounceTime(150)
      .distinctUntilChanged()
      .subscribe(() => {
        if (!this.dataSource) {
          return;
        }
        this.dataSource.filter = this.filter.nativeElement.value;
      });
  });
}




export class TableDataSource extends DataSource<Proces>{
  _filterChange = new BehaviorSubject('');
  get filter(): string {
    return this._filterChange.value;
  }
  set filter(filter: string) {
    this._filterChange.next(filter);
  }
  filteredData: any =[];

  constructor(private processes:Proces[]){
    super();
  }
  connect(): Observable<Proces[]>{
    const displayDataChanges = [
      this.processes,
      this._filterChange,
    ];
    return Observable.merge(...displayDataChanges).map(() => {
      this.filteredData = this.processes.slice().filter((item: Proces) => {
        const searchStr = (item.name).toLowerCase();
        return searchStr.indexOf(this.filter.toLowerCase()) !== -1;

      });
      return this.filteredData;
    })
  }
  disconnect(){}
}



      <div class="header">
    <mat-form-field floatPlaceholder="never">
      <input matInput #filter placeholder="Pretraži procese">
    </mat-form-field>
  </div>
  <mat-table #table [dataSource]="dataSource" class="table-mantis" matSort>

    <ng-container matColumnDef="col1">
      <mat-header-cell *matHeaderCellDef class="table-header-cell" mat-sort-header> Name</mat-header-cell>
      <mat-cell *matCellDef="let row" class="example-cell" > {{row.nazivProcesa}} </mat-cell>
    </ng-container>

    <ng-container matColumnDef="col2">
      <mat-header-cell *matHeaderCellDef class="table-header-cell" mat-sort-header> Cell 2</mat-header-cell>
      <mat-cell *matCellDef="let row" class="example-cell" > {{row.nazivVlasnika
        }} </mat-cell>
    </ng-container>

    <ng-container matColumnDef="col3">
      <mat-header-cell *matHeaderCellDef class="table-header-cell" mat-sort-header> Cell 3</mat-header-cell>
      <mat-cell *matCellDef="let row" class="example-cell" > {{row.interniAkt}} </mat-cell>
    </ng-container>

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

答案 3 :(得分:5)

使用Angular 8和Material 6.4.1时,如果您等待从服务接收数据,则修复MatSort和MatPaginator的最简单最好的方法是将 static:false 设置为true,像这样:

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

就我而言是ngOnChanges数据调用。

答案 4 :(得分:3)

我遇到了同样的问题,并通过添加以下内容解决了该问题:

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

@ViewChild(MatPaginator) set matPaginator(mp: MatPaginator) {
 this.paginator = mp;
this.setDataSourceAttributes();
 }

setDataSourceAttributes() {
  this.dataSource.paginator = this.paginator;
  this.dataSource.sort = this.sort;
  }

答案 5 :(得分:1)

之所以会这样,是因为在您的子视图“初始化”之前,您会调用 this.sort.sortChange 方法

  

您只需要从 AfterViewInit 实现类,而不是从 OnInit

     

并使用 ngAfterViewInit 生命周期方法

export class ApplicantListComponent implements AfterViewInit {
    @ViewChild(MatPaginator, { static: false }) paginator: MatPaginator;
    @ViewChild(MatSort, { static: false }) sort: MatSort;

    constructor() {}

    ngAfterViewInit() {
        this.sort.sortChange.subscribe(() => {
            this.paginator.pageIndex = 0;
            this.paginator.pageSize = this.pageSize;
        });
} 

答案 6 :(得分:0)

将异步数据从容器层传递到组件层时,我遇到了类似的问题。这是我的解决方法

因为元素开始时没有数据,所以没有像 original example 那样放置构造函数或OnInit的方法。只有在数据流进入(异步)之后,我才在setter中实现sort和paginator,并且一切正常。

在我的模板中:

<div class="card">

    <div class="card-header">
      <h4>{{pageTitle}}</h4>
      <mat-form-field>
        <input matInput (keyup)="applyFilter($event.target.value)" placeholder="Filter">
      </mat-form-field>
    </div>

    <div class="card-body p-0">    
      <div class="mat-elevation-z8">
        <table mat-table [dataSource]="dataSource" matSort>

          <ng-container matColumnDef="projectNumber">
            <th mat-header-cell *matHeaderCellDef mat-sort-header> Werf Nummer </th>
            <td mat-cell *matCellDef="let row"> W{{row.projectNumber}} </td>
          </ng-container>

          <ng-container matColumnDef="description">
            <th mat-header-cell *matHeaderCellDef mat-sort-header> Omschrijving </th>
            <td mat-cell *matCellDef="let row"> {{row.description}} </td>
          </ng-container>

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

        <mat-paginator [pageSizeOptions]="[10,20,100]"></mat-paginator>
      </div>      
    </div>
  </div>

在我的角度分量类中,

    export class ProjectListComponent {
      pageTitle = 'Projects';
      displayedColumns: string[] = ['projectNumber', 'description'];
      dataSource: MatTableDataSource<Project>;

      @ViewChild(MatPaginator, {static: true}) paginator: MatPaginator;
      @ViewChild(MatSort, {static: true}) sort: MatSort;
      @Input() set projects(value: Project[]){
        this.dataSource = new MatTableDataSource(value);
        this.dataSource.paginator = this.paginator;
        this.dataSource.sort = this.sort;
      }
      @Input() selectedProject: Project;
      @Output() selected = new EventEmitter<Project>();

      applyFilter(filterValue: string) {
        this.dataSource.filter = filterValue.trim().toLowerCase();

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

我应该提到一些关于过滤选项非常有趣的东西。请注意,这里的项目仅用于两个字段,但是接口实际上比该字段更多,例如它具有一个ID。即使我没有显示ID,也可以使用上面的代码对ID进行过滤,这真是太棒了。

    export interface Project {
        id: string;
        projectNumber: string;
        description: string;
        activePeriods: ProjectActivePeriod[];
    }

还要注意,您的displayColumns中的 matColumnDef =“ projectNumber” 引用必须是接口中属性的确切名称。如果我使用了“ P rojectNumber”,则排序将无法进行。

我根据

的信息进行构建

答案 7 :(得分:0)

我遇到了同样的问题,

此问题有两个原因

  1. 确保在 App模块
  2. 中包含了 MatSortModule 模块
 import { MatSortModule, MatPaginatorModule, MatTableModule } from '@angular/material';

 @NgModule({
  imports: [MatSortModule, MatPaginatorModule, MatTableModule],
  exports: []
})
  1. 确保您已在 ngAfterViewInit
  2. 中订阅了排序更改
  ngAfterViewInit() {
    this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0 );
  }

答案 8 :(得分:0)

如果数据在一个对象内,排序也不起作用。例如:

interface: Name { firstName: string; lastName: string; }
interface: User { name: Name; }

{{ user.Name.firstName }}

排序在这种情况下不起作用。它需要像:{{ user.firstName }}

此外,属性名称和列名称必须匹配。

答案 9 :(得分:0)

对我来说,我忘了把 matSort 道具放在 <table/> 上。

<table mat-table matSort [dataSource]="dataSource">