我该如何解决此错误及其原因?

时间:2019-05-18 10:31:02

标签: angular angular-material frontend angular-material-7

用排序标题实现 AngularMaterial 表我在控制台中遇到此错误:

错误TypeError:无法设置未定义的属性“ sort”     

以及终端中的此错误:

错误TS2740:类型'MatTableDataSource'缺少类型'Employee []'中的以下属性:length,pop,push,concat和另外24个。

错误TS2322:类型'MatSort'无法分配给类型'(compareFn ?:(a:雇员,b:雇员)=>数字)=>雇员[]'。

类型'MatSort'与签名'(compareFn ?:(a:Employee,b:Employee)=> number):Employee []'不匹配。

我无法从我那里得到想要的东西。我将不胜感激!

我使用了AngularMaterial文档中的代码,除了用于数据的接口。这会是一个问题吗?

EmployeeListComponent


import { Component, OnInit, ViewChild } from '@angular/core';
import { MatSort, MatTableDataSource } from '@angular/material';
import { AngularFirestore } from '@angular/fire/firestore';
import { EmployeeService } from '../shared/employee.service';
import { Employee } from '../shared/employee';

@Component({
  selector: 'app-employee-list',
  templateUrl: './employee-list.component.html',
  styleUrls: ['./employee-list.component.scss']
})
export class EmployeeListComponent implements OnInit {

  displayedColumns: string[] = ['fullname', 'position', 'mobile'];
  dataSource;

  @ViewChild(MatSort) sort: MatSort;

  constructor(private service: EmployeeService) { }

  ngOnInit() {
    this.service.getEmployees().subscribe(employees => {
      this.dataSource = new MatTableDataSource(employees);
      console.log(this.dataSource);
    });
    this.dataSource.sort = this.sort;

  }

}


EmployeeList HTML


<table mat-table [dataSource]="dataSource" matSort class="mat-elevation-z8">

  <!-- Position Column -->
  <ng-container matColumnDef="fullname">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Full Name </th>
    <td mat-cell *matCellDef="let element"> {{element.fullname}} </td>
  </ng-container>

  <!-- Name Column -->
  <ng-container matColumnDef="position">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Position </th>
    <td mat-cell *matCellDef="let element"> {{element.position}} </td>
  </ng-container>

  <!-- Weight Column -->
  <ng-container matColumnDef="mobile">
    <th mat-header-cell *matHeaderCellDef mat-sort-header> Mobile </th>
    <td mat-cell *matCellDef="let element"> {{element.mobile}} </td>
  </ng-container>

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


EmployeeService


getEmployees() {
    return this.firestore.collection<Employee>('employees')
      .snapshotChanges()
      .pipe(
        map(actions => actions.map(a => {
          const data = a.payload.doc.data();
          const id = a.payload.doc.id;
          return { id, ...data } as Employee;
       })
        )
      );
}

员工阶层


export class Employee {
  id: string;
  fullname: string;
  empCode: string;
  position: string;
  mobile: string;
}


2 个答案:

答案 0 :(得分:0)

总体而言,您的代码看起来还可以,但是这一行

this.dataSource.sort = this.sort;

放在错误的位置,应将其放在subscribe块中。

原因ERROR TypeError: Cannot set property 'sort' of undefined

您正在用异步方式混合同步代码,这意味着您的subscribe代码仅在返回API的响应(1-2秒)后才会执行,但this.dataSource.sort = this.sort;不会等待响应,因为它是同步代码,并且无论任何HTTP请求如何,它都将继续执行,并且您的dataSource对象将是undefined,因此您需要将其移入异步部分。

您的代码如下:

ngOnInit() {
    this.service.getEmployees().subscribe(employees => {
      this.dataSource = new MatTableDataSource(employees);
      console.log(this.dataSource);
      this.dataSource.sort = this.sort; <- note this line 

   });   
}

答案 1 :(得分:0)

您正在尝试从订阅外部访问数据,该数据应该在订阅内部。

此后,您将在this.sort挂钩中未定义ngOnInit时遇到麻烦,这是因为您试图访问尚未绘制的HTMLelement。 (MatSort)

您可以使用一个生命周期挂钩来确保@ViewChild可以随时访问视图,这是ngAfterViewInit,仅在绘制HTML时才会触发。

尝试这样的结构。


import { Component, AfterViewInit, ViewChild } from '@angular/core';
import { MatSort, MatTableDataSource } from '@angular/material';
import { AngularFirestore } from '@angular/fire/firestore';
import { EmployeeService } from '../shared/employee.service';
import { Employee } from '../shared/employee';

@Component({
  selector: 'app-employee-list',
  templateUrl: './employee-list.component.html',
  styleUrls: ['./employee-list.component.scss']
})
export class EmployeeListComponent implements AfterViewInit{

  displayedColumns: string[] = ['fullname', 'position', 'mobile'];
  dataSource;

  @ViewChild(MatSort) sort: MatSort;

  constructor(private service: EmployeeService) { }

  ngAfterViewInit(): void
  {
    this.service.getEmployees().subscribe(employees => {
      this.dataSource = new MatTableDataSource(employees);
      if (this.sort) // check it is defined.
      {
          this.dataSource.sort = this.sort;
      }
    });
  }

}

文档AfterViewInit Lifecycle // More details