Angular Material表格对接GraphQL后端实现分页与报错解决
问题原因
MatTableDataSource构造函数要求传入同步的数组类型数据,你传入的query_data是Apollo Client返回的Observable<Imp_Type[]>异步流对象,本身不具备数组的length、push等属性,因此触发类型不匹配报错。同时你代码里还存在2个隐含问题:
- 定义的
Imp_Type接口中imp_sub_group类型声明错误,实际GraphQL返回的是对象而非字符串 - 声明的
MatPaginator没有绑定到dataSource,分页功能不会生效
修正方案
步骤1:修正接口定义、调整属性声明
把Imp_Type的imp_sub_group类型改为正确的对象结构,同时不要直接初始化dataSource,先做声明。
步骤2:订阅Observable获取数据后初始化数据源
在ngOnInit中订阅query_data,拿到真实数组后再初始化MatTableDataSource,同时在ngAfterViewInit中绑定分页器。
完整修正代码
import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core'; import { MatPaginator } from '@angular/material/paginator'; import { MatTableDataSource } from '@angular/material/table'; import { Apollo, gql } from 'apollo-angular'; import { map } from 'rxjs/operators'; // 修正imp_sub_group的类型定义 interface ImpSubGroup { imp_group_id: string; sub_grou_name: string; } interface Imp_Type { uuid: string; imp_type_name: string; imp_sub_group: ImpSubGroup; } interface Response { imp_type: Imp_Type[] } // 新增分页参数变量,适配服务端分页 const GET_IMP_TYPE = gql` query Imp_Type($limit: Int!, $offset: Int!) { imp_type (limit: $limit, offset: $offset){ uuid imp_type_name imp_sub_group { imp_group_id sub_grou_name } } } `; @Component({ selector: 'app-imp-type', templateUrl: './imp-type.component.html', styleUrls: ['./imp-type.component.scss'] }) export class ImpTypeComponent implements OnInit, AfterViewInit { @ViewChild(MatPaginator) paginator: MatPaginator; displayedColumns: string[] = ['uuid', 'imp_type_name', 'sub_grou_name']; // 先声明数据源,不要直接初始化 dataSource: MatTableDataSource<Imp_Type>; constructor(private apollo: Apollo) { } ngOnInit(): void { // 首次加载默认取第一页10条数据 this.loadData(0, 10); } ngAfterViewInit(): void { // 监听分页切换事件,触发服务端分页请求 this.paginator.page.subscribe(event => { this.loadData(event.pageIndex * event.pageSize, event.pageSize); }) } // 封装数据加载逻辑 private loadData(offset: number, limit: number) { this.apollo.watchQuery<Response>({ query: GET_IMP_TYPE, variables: { limit, offset } }).valueChanges.pipe(map(result => result.data.imp_type)) .subscribe(data => { this.dataSource = new MatTableDataSource(data); this.dataSource.paginator = this.paginator; }) } }
额外说明
如果你的数据量不大,不需要服务端分页,可以直接一次性拉取所有数据,交由MatTableDataSource自带的客户端分页能力处理,不需要监听page事件重新请求接口。
内容的提问来源于stack exchange,提问作者Talip Akhan
相关产品推荐
相关产品推荐

