PrimeNG 9 - TreeTable Virtual Scroll - 节点选择丢失

Posted

技术标签:

【中文标题】PrimeNG 9 - TreeTable Virtual Scroll - 节点选择丢失【英文标题】:PrimeNG 9 - TreeTable Virtual Scroll - node selections get lost 【发布时间】:2016-04-19 15:50:34 【问题描述】:

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

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

可在此处找到最小可重现演示: https://stackblitz.com/edit/primeng9-treetablescroll-selections

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

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

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

已解决

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

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

【问题讨论】:

在你的例子中,我看不到任何代码。 @StPaulis - 我的错,演示链接已更新,谢谢 不确定您正在使用的那个版本发生了什么,但它似乎有问题..您提供的链接还链接到primeng9-treetablescroll-selections.stackblitz.io 以获取整页演示。我注意到最后一个元素应该是 999(它最初是)但是当我展开/折叠一行或两行时,994 最终以某种方式结束。我的直接想法是这是错误的,不要使用它。 @RobEvans - 如果这不是问题,我一开始就不会问这个问题! 很公平 :) 我个人会找到另一个使用的库,该库一开始显然没有损坏 【参考方案1】:

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

幸运的是,如果您想亲自动手,通过手动添加突出显示的课程,您可以解决此问题。看看updated 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 repository 上打开一个问题。

【讨论】:

感谢您的回复并提供了一个潜在的解决方案,这看起来确实是我可以采取的方向。但是,当重新选择\重新突出显示时会出现令人不快的闪烁 @mindparse 我也确实看到了,由于某种原因,当行展开折叠时,它与库有关为什么,但如果没有崇敬的工程,将很难指出,但这绝对是图书馆的问题。 似乎 treetabletoggler 和 treetable 都在监听点击事件,并在节点点击时分别发送展开/折叠和选定事件,因此出现了问题。如果您没有在扩展/合并事件处理程序中更新选定节点,您将看到跳跃选择行为。 嘿伙计,您建议的解决方法帮助我弄清楚了如何处理所选节点的设置闪烁为空并再次返回。请参阅我更新的问题以及指向新 stackblitz 的链接。问题在于,在 v9 中,当您切换父节点时,TreeTable 会触发节点选择事件和展开\折叠事件。现在这对我来说非常有用,并且将继续我们的项目,直到我们迁移到 v10。

以上是关于PrimeNG 9 - TreeTable Virtual Scroll - 节点选择丢失的主要内容,如果未能解决你的问题,请参考以下文章

jquery插件treetable使用

jQuery.treetable使用及异步加载

TreeTable相关操作

Spring Boot 入门:集成 treetable 和 zTree 实现树形图

[Layui]treetable加载layui图标

支持IE6的树形节结构TreeTable实际应用案例