Angular 角度材质:需要额外的交互才能触发渲染
我在使用角度材质时遇到了一种奇怪的行为:一些组件需要额外的事件(如在感兴趣的div上单击或鼠标移动)来触发实际渲染。 例如,对于mat表格,当它加载新行时,仍会显示一些空行,只要我向下滚动或单击其中一行,它们就会消失。 另一个例子是对话框:当我在边界外单击时,什么也没有发生,但如果我再次单击或滚动,它就会消失。 这是我的版本。 谢谢 首先,谢谢你的回答。 我注意到所有问题都链接到mat表:导致问题的对话框由表内的按钮触发,如果 我把它移到外面,它工作正常。 该表的组成部分如下所示:Angular 角度材质:需要额外的交互才能触发渲染,angular,typescript,angular-material,Angular,Typescript,Angular Material,我在使用角度材质时遇到了一种奇怪的行为:一些组件需要额外的事件(如在感兴趣的div上单击或鼠标移动)来触发实际渲染。 例如,对于mat表格,当它加载新行时,仍会显示一些空行,只要我向下滚动或单击其中一行,它们就会消失。 另一个例子是对话框:当我在边界外单击时,什么也没有发生,但如果我再次单击或滚动,它就会消失。 这是我的版本。 谢谢 首先,谢谢你的回答。 我注意到所有问题都链接到mat表:导致问题的对话框由表内的按钮触发,如果 我把它移到外面,它工作正常。 该表的组成部分如下所示: expor
export class MainComponent implements OnInit {
dataSource : MyTableSource;
@ViewChild(MatTable, {static:true}) table: MatTable<any>;
dtOptions: any = {
displayedColumns : [ 'colA', 'colB', 'colC', 'colD'],
search : { value : "" } ,
order : { name : 'values' , asc : true },
subset : [] ,
pageSize : 10,
pageIndex : 0,
draw : 0 ,
recordsTotal : 0,
recordsFiltered : 0};
constructor(public dialog: MatDialog,
private _snackBar: MatSnackBar,private trackService: TracksService) {
};
ngOnInit() {
this.dataSource = new KmerTableSource(this.trackService);
}
refreshTable(event?:any){
if ( event){
if ( event.pageSize){
this.dtOptions.pageSize=event.pageSize;
this.dtOptions.pageIndex=event.pageIndex;
}
if (event.active){
this.dtOptions.order.name = event.active;
this.dtOptions.order.asc = event.direction == "asc";
}
}
this.dataSource.loadData(this.dtOptions);
}
}
导出类MainComponent实现OnInit{
数据源:MyTableSource;
@ViewChild(MatTable,{static:true})table:MatTable;
dtOptions:any={
显示列:['colA'、'colB'、'colC'、'colD'],
搜索:{值:},
顺序:{name:'values',asc:true},
子集:[],
页面大小:10,
页面索引:0,
抽签:0,
记录总数:0,
已筛选的记录:0};
构造函数(公共对话框:MatDialog,
私人(snackBar:matsnakbar,私人轨道服务:tracks服务){
};
恩戈尼尼特(){
this.dataSource=新的KmerTableSource(this.trackService);
}
刷新表(事件?:任何){
如果(事件){
if(event.pageSize){
this.dtOptions.pageSize=event.pageSize;
this.dtOptions.pageIndex=event.pageIndex;
}
如果(事件激活){
this.dtOptions.order.name=event.active;
this.dtOptions.order.asc=event.direction==“asc”;
}
}
this.dataSource.loadData(this.dtOptions);
}
}
html
<table mat-table matSort (matSortChange)="refreshTable($event)" [dataSource]="dataSource" >
<ng-container matColumnDef="importance">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Col A</th>
<td mat-cell *matCellDef="let row">{{row.A}}</td>
</ng-container>
<ng-container matColumnDef="kmer">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Col B</th>
<td mat-cell *matCellDef="let row">{{row.B}}</td>
</ng-container>
<ng-container matColumnDef="position">
<th mat-header-cell *matHeaderCellDef mat-sort-header>Col C</th>
<td mat-cell *matCellDef="let row">{{row.C}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="dtOptions.displayedColumns;sticky : true;"></tr>
<tr mat-row cdk-row *matRowDef="let row; columns: dtOptions.displayedColumns"></tr>
</table>
科拉
{{row.A}}
B列
{{row.B}}
C柱
{{row.C}}
数据源
@Injectable({
providedIn: 'root'
})
export class MyTableSource implements DataSource<DataPoint> {
private dataSubject = new BehaviorSubject<DataPoint[]>([]);
constructor(private trackService :TracksService ) { }
connect(collectionViewer: CollectionViewer): Observable<DataPoint[]> {
return this.dataSubject.asObservable();
}
disconnect(collectionViewer: CollectionViewer): void {
this.dataSubject.complete();
}
loadData(request : any) {
this.trackService.getDataTable(request).pipe(
catchError(()=>of([])),
).subscribe(response => {
this.dataSubject.next(response);
});
}
}
@注射的({
providedIn:'根'
})
导出类MyTableSource实现数据源{
私有数据主体=新行为主体([]);
构造函数(专用跟踪服务:跟踪服务){}
连接(collectionViewer:collectionViewer):可观察{
返回此.dataSubject.asObservable();
}
断开连接(collectionViewer:collectionViewer):无效{
this.dataSubject.complete();
}
loadData(请求:任何){
这个.trackService.getDataTable(请求).pipe(
catchError(()=>of([]),的,
).订阅(响应=>{
this.dataSubject.next(响应);
});
}
}
轨道服务(我使用的是electron)
@可注射({
providedIn:'根'
} )
导出类TracksService{
受保护请求:编号=0;
受保护的ipc:ipc;
构造函数(受保护的http:HttpClient){
如果((窗口).require){
试一试{
this.ipc=(window).require(“electron”).ipc渲染器;
}捕获(错误){
投掷误差;
}
}否则{
控制台。警告(“无法加载电子ipc”);
}
}
getDataTable(dataTablesParameters:any):可观察{
var id=this.request;
该请求+=1;
this.ipc.send(“getData”、id、dataTablesParameters);
返回新的可观察对象(观察者=>{
此.ipc.once(“getData-”+id,(事件,参数)=>{
dataTablesParameters.recordsTotal=arg.recordsTotal;
dataTablesParameters.recordsFiltered=arg.recordsFiltered;
下一步(参数数据);
});
});
}
}
我也遇到了类似的情况,因为我使用了从Input()值获取其值的材质组件。需要在ngOnChanges或NgoAfterContentInit上使用ChangeDetectorRef
export class MyComponent {
@Input() data: string[];
constructor(private cd: ChangeDetectorRef) { }
ngAfterContentInit() {
this.cd.detectChanges();
}
}
您可能需要更改策略以推动:
@Component({
...
changeDetection: ChangeDetectionStrategy.OnPush
...
})
使用NgZone和ChangeDetectorRef解决:可能调用是在MatTable组件内部进行的,订阅中的更改没有在主组件中呈现 在主要组成部分:
refreshTable(event?:any){
...
this.dataSource.loadData(this.dtOptions).then(()=>this.cd.markForCheck());
}
数据源的loadData现在必须返回一个承诺,以便在加载后触发markForCheck
loadData(request : any) : Promise<void> {
return new Promise(resolve, reject )=>{...})
}
感谢@gsa.interactive提供的ChangeDetectorRef提示,您能否添加一个发生这种行为的简单示例?我强烈怀疑没有触发ChangeDetection。在
ngOnChanges
中使用detectChanges
是您绝对不想做的事情。使用限制性更强的ChangeDetectionStrategy
例如onPush
确实是可取的(从性能上看),但无助于解决这个问题。感谢您的提示,但我认为问题来自数据表,而不是对话框本身
refreshTable(event?:any){
...
this.dataSource.loadData(this.dtOptions).then(()=>this.cd.markForCheck());
}
loadData(request : any) : Promise<void> {
return new Promise(resolve, reject )=>{...})
}
this.zone.run(()=>{this.dialog.open(...)}));