Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/401.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript MatSort和MatPaginator在没有设置超时的情况下不工作_Javascript_Angular_Sorting_Pagination_Angular Material - Fatal编程技术网

Javascript MatSort和MatPaginator在没有设置超时的情况下不工作

Javascript MatSort和MatPaginator在没有设置超时的情况下不工作,javascript,angular,sorting,pagination,angular-material,Javascript,Angular,Sorting,Pagination,Angular Material,我有一个来自端点的数据,并将其放入MatTableDataSource。我能够让它为MatSort和MatPaginator工作,但需要使用setTimeOut,这似乎不是一种正确的方法。如果我删除它,它会抱怨“无法读取未定义的排序属性”,我认为这是因为它尚未初始化 我也尝试过: 将其移动到afterviewinit,但数据是在 调用afterviewinit后,它仍然无法工作 在this.datasource之后使用this.changeDetectorRef.detectChanges()

我有一个来自端点的数据,并将其放入MatTableDataSource。我能够让它为MatSort和MatPaginator工作,但需要使用setTimeOut,这似乎不是一种正确的方法。如果我删除它,它会抱怨“无法读取未定义的排序属性”,我认为这是因为它尚未初始化

我也尝试过:

  • 将其移动到afterviewinit,但数据是在 调用afterviewinit后,它仍然无法工作
  • 在this.datasource之后使用this.changeDetectorRef.detectChanges()= 新的。。。也不起作用
这是我当前的代码(正在工作,但使用settimeout)


// ... 一些html来显示“记录”
组件

export class ResultsComponent implements OnInit, OnDestroy, AfterViewInit {
    dataSource: MatTableDataSource<any> = new MatTableDataSource();
    renderedData: Observable<any>;

    @ViewChild(MatPaginator) paginator: MatPaginator;
    @ViewChild(MatSort) sort: MatSort;

    constructor(some service) {}

    ngOnInit() {
        const accountId = someOtherService.getAccountId();
        this.someService.getData(accountId)
            .subscribe((myData) => {
                    this.dataSource = new MatTableDataSource(myData);

                    // it won't work properly if it is not wrapped in timeout
                    setTimeout(() => {
                        this.dataSource.paginator = this.paginator;
                        this.sort.sort(<MatSortable>({id: 'created_on', start: 'desc'}));
                        this.dataSource.sort = this.sort;
                    });

                    this.renderedData = this.dataSource.connect();
                }
            });
    }

    ngAfterViewInit() {
    }

    ngOnDestroy(): void {
        if (this.dataSource) { this.dataSource.disconnect(); }
    }
}
导出类ResultComponent实现OnInit、OnDestroy、AfterViewInit{
dataSource:MatTableDataSource=新MatTableDataSource();
渲染数据:可观察;
@ViewChild(MatPaginator)分页器:MatPaginator;
@ViewChild(MatSort)排序:MatSort;
构造函数(某些服务){}
恩戈尼尼特(){
const accountId=someOtherService.getAccountId();
this.someService.getData(accountId)
.订阅((myData)=>{
this.dataSource=新MatTableDataSource(myData);
//如果它没有包装在timeout中,它将无法正常工作
设置超时(()=>{
this.dataSource.paginator=this.paginator;
sort.sort({id:'created_on',start:'desc'}));
this.dataSource.sort=this.sort;
});
this.renderData=this.dataSource.connect();
}
});
}
ngAfterViewInit(){
}
ngOnDestroy():void{
如果(this.dataSource){this.dataSource.disconnect();}
}
}

上面的代码对我很有用,如果可能的话,我只是在寻找不使用settimeout的正确方法。

这里有几个生命周期计时问题,仔细想想,这是正确的

MatSort是视图的一部分,因此在OnInit期间它还没有“就绪”——它是未定义的。因此,尝试使用它会抛出错误

MatSort在AfterViewInit中已经准备好了,但由于在执行排序后需要将排序“应用”到数据源,并且这会通过“连接”到数据源的RenderData触发对视图的更改,因此情况更加复杂。因此,您将得到一个表达式ChangedTerithasBeenCheckedError,因为视图初始化生命周期尚未完成,但您已经在尝试更改它

因此,在视图准备就绪之前无法进行排序,并且在收到视图准备就绪的通知时无法应用排序。您唯一能做的就是等待组件初始化生命周期结束。您可以使用setTimeout()实现这一点

如果没有setTimeout(),我认为无法解决这两个问题,因此在这种情况下,无论是从OnInit还是AfterViewInit调用它都无关紧要

关于您的代码的几个其他观察结果:

您不需要在订阅中创建MatTableDataSource的新实例。您可以将结果数据分配给已创建的数据源:

this.dataSource.data = myData;
dataSource: MatTableDataSource<any> = new MatTableDataSource();
renderedData: Observable<any> = this.dataSource.connect();
这使您无需在事后将渲染数据连接到数据源,因此可以在初始化数据源时执行此操作:

this.dataSource.data = myData;
dataSource: MatTableDataSource<any> = new MatTableDataSource();
renderedData: Observable<any> = this.dataSource.connect();
dataSource:MatTableDataSource=new MatTableDataSource();
RenderData:Observable=this.dataSource.connect();

实际上有一种方法可以在不使用setTimeout的情况下执行此操作。这适用于Angular 9,我还没有在以前的版本中测试过它,所以我不确定它是否适用于Angular 9

我在这里找到了这个解决方案:

而不是把:

@ViewChild(MatSort) sort: MatSort;
使用一个设置器进行matSort。一旦模板中的matSort更改(即第一次定义),此setter将触发,当您通过单击箭头更改排序时,它将不会触发。这将如下所示:

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

您可以对分页器使用相同的解决方案。

通过订阅创建MatTableDataSource时,我也必须这样做。。期待看到这个问题的答案。一个稍微好一点的解决方法可能是在
this.dataSource=…
之后调用
ChangeDetectorRef.detectures()
,而不是使用
setTimeout
。@ConnorsFan尝试了它,它给了我“无法读取SafeSubscriber上未定义的属性'排序'。\u next”。我在构造函数中添加私有changeDetectorRef:changeDetectorRef,然后在下面这个.datasource=new Mat。。。this.changeDetectorRef.detectChanges()@ConnorsFan,
detectChanges
运行对当前视图和所有子项的完整检查,这是一种非常昂贵的方法,而且空
setTimeout
与这种方法相比看起来并不像邪恶的解释。非常感谢。我可能应该打开一个新的问题,但是在排序发生后是否仍然可以检索第一个元素?与
*ngFor
div中的一个相同的代码元素?获取外部DIV(带有
*ngIf=“!isLoading”
)并抓取第一个孩子。很好!(我想这是可行的。)