1

在我正在处理的应用程序中,我面临一个 PrimeNG 9 TreeTable 的奇怪问题,我已经配置了虚拟滚动和具有切换\扩展行为的嵌套节点结构。

我在做出选择后发现,滚动或展开另一个节点时突出显示的节点会丢失。突出显示的选择会跳转到另一个随机节点。

可以在这里找到最小的可重现演示: https ://stackblitz.com/edit/primeng9-treetablescroll-selections

我想知道这是否与this.cdr.detectChanges();我在ngAfterViewInit生命周期钩子中添加的有关,我添加它是为了在 v10.0.3 版本中引入此错误修复,但删除它没有任何区别,并带回错误修复地​​址ExpressionChangedAfterItHasBeenCheckedError

该应用程序也无法迁移到 PrimeNG 10,因此我特意寻找 v9 修复\解决方法(如果可能)。

有人知道这里可能发生了什么吗?

解决了

感谢@DipenShah 为我指明了正确的方向以找到合适的解决方法。根据他的回答,我进一步增强了他的方法,以处理在 v9 中树表在切换父节点时触发展开\折叠事件和节点选择事件的情况。这在 v10 中不会发生。

我的最终解决方法在这里https://stackblitz.com/edit/primeng9-treetablescroll-selections-utsj2p?file=src/app/app.component.ts

4

1 回答 1

1

在滚动期间重用视图之前,库本身和回收视图似乎存在问题。

幸运的是,如果您想亲自动手,通过手动添加突出显示的类,您可以解决问题。看看更新的 stackblitz

app.component.ts

import {AfterViewInit, ChangeDetectorRef,  Component,OnDestroy,OnInit, ViewChild} from '@angular/core';
import {NodeService} from './nodeservice';
import {TreeNode} from 'primeng/api';
// import { PrimeNGConfig } from 'primeng/api';
import { TreeTable } from 'primeng/treetable';
import { Subscription } from 'rxjs';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements AfterViewInit, OnDestroy { 
    
    @ViewChild(TreeTable)
    private virtualTable: TreeTable;

    virtualFiles: TreeNode[];
    selectedNode: TreeNode;

    cols: any[];
  
    private virtualTableSub: Subscription;

    constructor(private cdr: ChangeDetectorRef) { }

    ngOnInit() {
        this.virtualFiles = Array.from({length: 1000}).map((_,i) => this.createNode(i, 100));

        this.cols = [
            { field: 'name', header: 'Name' },
            { field: 'size', header: 'Size' },
            { field: 'type', header: 'Type' }
        ];
    }

    expanded(e) {
      this.selectedNode = null;
      setTimeout(() => {
        this.selectedNode = e.node;
        this.cdr.detectChanges();
      });
    }

    collapsed(e) {
      this.selectedNode = null;
      setTimeout(() => {
        this.selectedNode = e.node;
        this.cdr.detectChanges();
      });
    }

    ngAfterViewInit() {
      this.virtualTableSub = this.virtualTable.tableService.uiUpdateSource$.subscribe(() => {
        if (this.virtualTable.virtualScroll) {
          this.cdr.detectChanges();
        }
      });
    }

    ngOnDestroy() {
      this.virtualTableSub?.unsubscribe();
    }

    createNode(i: number, children: number): TreeNode {
        let node: TreeNode = {
            data: {name: 'Node ' + i, type: 'virtual node', size: Math.ceil(Math.random() * 10000) + 'kb'},
            children: Array.from({length: children}).map((_,j) => {
                return { 
                    data: {name: 'Node ' + i + '.' + j, type: 'virtual child node', size: Math.ceil(Math.random() * 10000) + 'kb'}
                }
            })
        };

        return node;
    }
}

app.component.html

<div class="card">
    <h5>Full Page Scroll</h5>
    <p>FlexScroll can also be used for cases where scrollable viewport should be responsive with respect to the window
        size. See the <a [routerLink]="['/treetable/flexscroll']">Full Page</a> demo for an example.</p>

    <h5>Virtual Scroll with 100000 Nodes</h5>
    <p-treeTable #treeTable [value]="virtualFiles" [columns]="cols" [scrollable]="true" [rows]="100"
        selectionMode="single" [(selection)]="selectedNode" (onNodeExpand)="expanded($event)"
        (onNodeCollapse)="collapsed($event)" scrollHeight="200px" [virtualScroll]="true" [virtualRowHeight]="34"
        dataKey="name">
        <ng-template pTemplate="header" let-columns>
            <tr>
                <th *ngFor="let col of columns">
                    {{col.header}}
                </th>
            </tr>
        </ng-template>
        <ng-template pTemplate="body" let-rowNode let-rowData="rowData" let-columns="columns">
            <tr [ttRow]="rowNode" [ttSelectableRow]="rowNode" style="height:34px"
                [ngClass]="{ 'highlighted' : selectedNode?.data === rowData }">
                <td *ngFor="let col of columns; let i = index">
                    <p-treeTableToggler [rowNode]="rowNode" *ngIf="i == 0"></p-treeTableToggler>
                    {{rowData[col.field]}}
                </td>
            </tr>
        </ng-template>
    </p-treeTable>
</div>

app.component.scss

::ng-deep.ui-treetable .ui-treetable-tbody > tr.highlighted {
  background-color: #57a0d7;
  color: #fff;
}

我鼓励您在图书馆的github 存储库上打开一个问题。

于 2020-10-26T17:02:12.703 回答