Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature : Add virtual scroll on Tree Select Component #13771

Merged
merged 9 commits into from
Mar 22, 2024
8 changes: 8 additions & 0 deletions src/app/components/treeselect/treeselect.css
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,12 @@
.p-treeselect-clearable {
position: relative;
}

.p-treeselect-virtual-scroll .p-tree.p-component {
padding: 0;
}

.p-treeselect-virtual-scroll .p-tree-container.p-scroller-content {
padding: 1.25rem;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm not wrong this styles themes should be in primeng-sass-theme project: https://github.com/primefaces/primeng-sass-theme/
Maybe @cetincakiroglu can confirm you

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can i have a confirmation ?

}
}
22 changes: 20 additions & 2 deletions src/app/components/treeselect/treeselect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { AnimationEvent } from '@angular/animations';
import { CommonModule } from '@angular/common';
import { AfterContentInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChildren, ElementRef, EventEmitter, forwardRef, Input, NgModule, Output, QueryList, TemplateRef, ViewChild, ViewEncapsulation } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { OverlayOptions, OverlayService, PrimeNGConfig, PrimeTemplate, SharedModule, TreeNode } from 'primeng/api';
import { OverlayOptions, OverlayService, PrimeNGConfig, PrimeTemplate, ScrollerOptions, SharedModule, TreeNode } from 'primeng/api';
import { DomHandler } from 'primeng/dom';
import { ChevronDownIcon } from 'primeng/icons/chevrondown';
import { SearchIcon } from 'primeng/icons/search';
Expand Down Expand Up @@ -113,7 +113,7 @@ export const TREESELECT_VALUE_ACCESSOR: any = {
</span>
</button>
</div>
<div class="p-treeselect-items-wrapper" [ngStyle]="{ 'max-height': scrollHeight }">
<div class="p-treeselect-items-wrapper" [class.p-treeselect-virtual-scroll]="virtualScroll" [ngStyle]="{ 'max-height': scrollHeight }" >
<p-tree
#tree
[value]="options"
Expand All @@ -133,6 +133,9 @@ export const TREESELECT_VALUE_ACCESSOR: any = {
[filterPlaceholder]="filterPlaceholder"
[filterLocale]="filterLocale"
[filteredNodes]="filteredNodes"
[virtualScroll]="virtualScroll"
[virtualScrollItemSize]="virtualScrollItemSize"
[virtualScrollOptions]="virtualScrollOptions"
[_templateMap]="templateMap"
>
<ng-container *ngIf="emptyTemplate">
Expand Down Expand Up @@ -314,6 +317,21 @@ export class TreeSelect implements AfterContentInit {
* @group Props
*/
@Input() resetFilterOnHide: boolean = true;
/**
* Whether the data should be loaded on demand during scroll.
* @group Props
*/
@Input() virtualScroll: boolean | undefined;
/**
* Height of an item in the list for VirtualScrolling.
* @group Props
*/
@Input() virtualScrollItemSize: number | undefined;
/**
* Whether to use the scroller feature. The properties of scroller component can be used like an object in it.
* @group Props
*/
@Input() virtualScrollOptions: ScrollerOptions | undefined;
/**
* An array of treenodes.
* @defaultValue undefined
Expand Down
3 changes: 2 additions & 1 deletion src/app/showcase/doc/treeselect/treeselectdoc.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ import { InvalidDoc } from './invaliddoc';
import { MultipleDoc } from './multipledoc';
import { ReactiveFormsDoc } from './reactiveformsdoc';
import { StyleDoc } from './styledoc';
import { VirtualScrollDoc } from './virtualscrolldoc';

@NgModule({
imports: [CommonModule, AppCodeModule, AppDocModule, TreeSelectModule, FormsModule, ReactiveFormsModule, RouterModule],
exports: [AppDocModule],
declarations: [ImportDoc, BasicDoc, MultipleDoc, CheckboxDoc, FilterDoc, FloatLabelDoc, InvalidDoc, DisabledDoc, StyleDoc, AccessibilityDoc, ReactiveFormsDoc]
declarations: [ImportDoc, BasicDoc, MultipleDoc, CheckboxDoc, VirtualScrollDoc, FilterDoc, FloatLabelDoc, InvalidDoc, DisabledDoc, StyleDoc, AccessibilityDoc, ReactiveFormsDoc]
})
export class TreeSelectDocModule {}
58 changes: 58 additions & 0 deletions src/app/showcase/doc/treeselect/virtualscrolldoc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Component, Input } from '@angular/core';
import { Code } from '../../domain/code';
import { NodeService } from '../../service/nodeservice';

@Component({
selector: 'virtual-scroll-doc',
template: ` <section class="py-3">
<app-docsectiontext [title]="title" [id]="id">
<p>VirtualScrolling is an efficient way of rendering the options by displaying a small subset of data in the viewport at any time. When dealing with huge number of options, it is suggested to enable VirtualScrolling to avoid performance
issues. Usage is simple as setting <i>virtualScroll</i> property to true and defining <i>virtualScrollItemSize</i> to specify the height of an item.</p>
</app-docsectiontext>
<div class="card flex justify-content-center">
<p-treeSelect class="w-full md:w-20rem" containerStyleClass="w-full" [(ngModel)]="selectedNodes" [options]="nodes" display="chip" [metaKeySelection]="false" selectionMode="checkbox" placeholder="Select Item"
[virtualScroll]="true" [virtualScrollItemSize]="46" [virtualScrollOptions]="{ scrollHeight: '200px' }"></p-treeSelect>
</div>
<app-code [code]="code" selector="tree-select-virtual-scroll-demo"></app-code>
</section>`
})
export class VirtualScrollDoc {
@Input() id: string;

@Input() title: string;

nodes!: any[];

selectedNodes: any;

constructor(private nodeService: NodeService) {
this.nodeService.getLargeTreeNodes().then((files) => (this.nodes = files));
}

code: Code = {
basic: `<p-treeSelect class="w-full md:w-20rem" containerStyleClass="w-full" [(ngModel)]="selectedNodes" [options]="nodes" display="chip" [metaKeySelection]="false" selectionMode="checkbox" placeholder="Select Item" [virtualScroll]="true" [virtualScrollItemSize]="46" [virtualScrollOptions]="{scrollHeight: '200px'}"></p-treeSelect>`,
html: `
<div class="card flex justify-content-center">
<p-treeSelect class="w-full md:w-20rem" containerStyleClass="w-full" [(ngModel)]="selectedNodes" [options]="nodes" display="chip" [metaKeySelection]="false" selectionMode="checkbox" placeholder="Select Item" [virtualScroll]="true" [virtualScrollItemSize]="46" [virtualScrollOptions]="{scrollHeight: '200px'}"></p-treeSelect>
</div>`,
typescript: `
import { Component } from '@angular/core';
import { NodeService } from '../../service/nodeservice';

@Component({
selector: 'tree-select-virtual-scroll-demo',
templateUrl: './tree-select-virtual-scroll-demo.html'
})
export class TreeSelectVirtualScrollDemo {
nodes!: any[];

selectedNodes: any;

constructor(private nodeService: NodeService) {
this.nodeService.getLargeTreeNodes().then((files) => (this.nodes = files));
}
}`,

service: ['NodeService'],
};
}
6 changes: 6 additions & 0 deletions src/app/showcase/pages/treeselect/treeselectdemo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { ImportDoc } from '../../doc/treeselect/importdoc';
import { InvalidDoc } from '../../doc/treeselect/invaliddoc';
import { MultipleDoc } from '../../doc/treeselect/multipledoc';
import { StyleDoc } from '../../doc/treeselect/styledoc';
import { VirtualScrollDoc } from '../../doc/treeselect/virtualscrolldoc';

@Component({
templateUrl: './treeselectdemo.html'
Expand Down Expand Up @@ -41,6 +42,11 @@ export class TreeSelectDemo {
label: 'Checkbox',
component: CheckboxDoc
},
{
id: 'virtual-scroll-doc',
label: 'Virtual Scroll',
component: VirtualScrollDoc
},
{
id: 'filter',
label: 'Filter',
Expand Down
30 changes: 30 additions & 0 deletions src/app/showcase/service/nodeservice.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Injectable } from '@angular/core';
import { TreeNode } from "../../components/api/treenode";

@Injectable()
export class NodeService {
Expand Down Expand Up @@ -763,6 +764,35 @@ export class NodeService {
];
}

getDynamicTreeNodes(parentCount: number, childrenCount: number): TreeNode[] {
GaetanRouzies marked this conversation as resolved.
Show resolved Hide resolved
const nodes: TreeNode[] = [];

for (let parentIndex = 0; parentIndex < parentCount; parentIndex++) {
const children: TreeNode[] = [];

for (let childIndex = 0; childIndex < childrenCount; childIndex++) {
children.push({
key: `${parentIndex}-${childIndex}`,
label: `Child ${parentIndex}-${childIndex}`,
selectable: true,
});
}

nodes.push({
key: parentIndex.toString(),
label: `Parent ${parentIndex}`,
selectable: true,
children: children,
});
}

return nodes;
}

getLargeTreeNodes() {
return Promise.resolve(this.getDynamicTreeNodes(10, 100));
}

getTreeTableNodes() {
return Promise.resolve(this.getTreeTableNodesData());
}
Expand Down