From a263a2e270adb919153946841229258b7d538dec Mon Sep 17 00:00:00 2001 From: Sergey Andrievskiy Date: Fri, 22 Feb 2019 18:46:04 +0300 Subject: [PATCH] refactor(tree-grid): allow specify getters for node properties (#1254) --- docs/structure.ts | 1 - src/app/playground-components.ts | 6 + .../data-source/tree-grid-data-source.ts | 26 +++-- .../data-source/tree-grid-data.service.ts | 42 ++++--- .../data-source/tree-grid-filter.service.ts | 2 +- .../tree-grid/data-source/tree-grid.model.ts | 59 ++++------ .../data-source/tree-grid.service.ts | 2 +- .../tree-grid/tree-grid-cell.component.ts | 4 +- .../tree-grid/tree-grid.component.spec.ts | 106 ++++++++++++++++-- .../tree-grid/tree-grid.component.ts | 17 ++- .../tree-grid/tree-grid-basic.component.ts | 9 +- .../tree-grid-custom-icons.component.ts | 10 +- ...ee-grid-custom-node-structure.component.ts | 99 ++++++++++++++++ ...ree-grid-disable-click-toggle.component.ts | 9 +- .../tree-grid-filterable.component.ts | 10 +- .../tree-grid-responsive.component.ts | 9 +- .../tree-grid/tree-grid-routing.module.ts | 5 + .../tree-grid/tree-grid-showcase.component.ts | 16 +-- .../tree-grid/tree-grid-sortable.component.ts | 16 +-- .../with-layout/tree-grid/tree-grid.module.ts | 2 + 20 files changed, 342 insertions(+), 108 deletions(-) create mode 100644 src/playground/with-layout/tree-grid/tree-grid-custom-node-structure.component.ts diff --git a/docs/structure.ts b/docs/structure.ts index 487fc5a07e..e5a9315d05 100644 --- a/docs/structure.ts +++ b/docs/structure.ts @@ -492,7 +492,6 @@ export const structure = [ icon: 'tree-grid.svg', source: [ 'NbTreeGridComponent', - 'NbTreeGridNode', 'NbTreeGridPresentationNode', 'NbTreeGridSortService', 'NbTreeGridFilterService', diff --git a/src/app/playground-components.ts b/src/app/playground-components.ts index 32ce7d1ed7..041db09010 100644 --- a/src/app/playground-components.ts +++ b/src/app/playground-components.ts @@ -1301,6 +1301,12 @@ export const PLAYGROUND_COMPONENTS: ComponentLink[] = [ component: 'TreeGridDisableClickToggleComponent', name: 'Tree Grid Disable Click Toggle', }, + { + path: 'tree-grid-custom-node-structure.component', + link: '/tree-grid/tree-grid-custom-node-structure.component', + component: 'TreeGridCustomNodeStructureComponent', + name: 'Tree Grid Custom Node Structure', + }, ], }, { diff --git a/src/framework/theme/components/tree-grid/data-source/tree-grid-data-source.ts b/src/framework/theme/components/tree-grid/data-source/tree-grid-data-source.ts index b181d05bab..d195232d7a 100644 --- a/src/framework/theme/components/tree-grid/data-source/tree-grid-data-source.ts +++ b/src/framework/theme/components/tree-grid/data-source/tree-grid-data-source.ts @@ -8,14 +8,14 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject, combineLatest, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; -import { NbDataSource } from '../../cdk/table'; import { NbCollectionViewer } from '../../cdk/collections'; -import { NbTreeGridSortService } from './tree-grid-sort.service'; +import { NbDataSource } from '../../cdk/table'; +import { NbSortable, NbSortRequest } from '../tree-grid-sort.component'; +import { NbTreeGridDataService } from './tree-grid-data.service'; import { NbTreeGridFilterService } from './tree-grid-filter.service'; +import { NbTreeGridSortService } from './tree-grid-sort.service'; +import { NbGetters, NB_DEFAULT_ROW_LEVEL, NbTreeGridPresentationNode } from './tree-grid.model'; import { NbToggleOptions, NbTreeGridService } from './tree-grid.service'; -import { NbTreeGridDataService } from './tree-grid-data.service'; -import { NbSortable, NbSortRequest } from '../tree-grid-sort.component'; -import { DEFAULT_ROW_LEVEL, NbTreeGridNode, NbTreeGridPresentationNode } from './tree-grid.model'; export interface NbFilterable { filter(filterRequest: string); @@ -40,10 +40,12 @@ export class NbTreeGridDataSource extends NbDataSource[]) { - const presentationData: NbTreeGridPresentationNode[] = data - ? this.treeGridDataService.toPresentationNodes(data) - : []; + setData(data: N[], customGetters?: NbGetters) { + let presentationData: NbTreeGridPresentationNode[] = []; + if (data) { + presentationData = this.treeGridDataService.toPresentationNodes(data, customGetters); + } + this.data = new BehaviorSubject(presentationData); this.updateChangeSubscription(); } @@ -81,7 +83,7 @@ export class NbTreeGridDataSource extends NbDataSource { private treeGridDataService: NbTreeGridDataService) { } - create(data: NbTreeGridNode[]): NbTreeGridDataSource { + create(data: N[], customGetters?: NbGetters): NbTreeGridDataSource { const dataSource = new NbTreeGridDataSource( this.sortService, this.filterService, @@ -138,7 +140,7 @@ export class NbTreeGridDataSourceBuilder { this.treeGridDataService, ); - dataSource.setData(data); + dataSource.setData(data, customGetters); return dataSource; } } diff --git a/src/framework/theme/components/tree-grid/data-source/tree-grid-data.service.ts b/src/framework/theme/components/tree-grid/data-source/tree-grid-data.service.ts index 3b182a6745..f558c33047 100644 --- a/src/framework/theme/components/tree-grid/data-source/tree-grid-data.service.ts +++ b/src/framework/theme/components/tree-grid/data-source/tree-grid-data.service.ts @@ -3,22 +3,41 @@ * Copyright Akveo. All Rights Reserved. * Licensed under the MIT License. See License.txt in the project root for license information. */ + import { Injectable } from '@angular/core'; -import { DEFAULT_ROW_LEVEL, NbTreeGridNode, NbTreeGridPresentationNode } from './tree-grid.model'; +import { NbGetters, NB_DEFAULT_ROW_LEVEL, NbTreeGridPresentationNode } from './tree-grid.model'; @Injectable() export class NbTreeGridDataService { - toPresentationNodes(nodes: NbTreeGridNode[], level: number = DEFAULT_ROW_LEVEL): NbTreeGridPresentationNode[] { - return nodes.map((node: NbTreeGridNode) => { - const presentationNode = new NbTreeGridPresentationNode(node, level); + private defaultGetters: NbGetters = { + dataGetter: node => node.data, + childrenGetter: d => d.children || undefined, + expandedGetter: d => !!d.expanded, + }; + + toPresentationNodes( + nodes: N[], + customGetters?: NbGetters, + level: number = NB_DEFAULT_ROW_LEVEL, + ): NbTreeGridPresentationNode[] { + const getters: NbGetters = { ...this.defaultGetters, ...customGetters }; + + return this.mapNodes(nodes, getters, level); + } - if (node.children) { - presentationNode.children = this.toPresentationNodes(node.children, level + 1); + private mapNodes(nodes: N[], getters: NbGetters, level: number): NbTreeGridPresentationNode[] { + const { dataGetter, childrenGetter, expandedGetter } = getters; + + return nodes.map(node => { + const childrenNodes = childrenGetter(node); + let children: NbTreeGridPresentationNode[]; + if (childrenNodes) { + children = this.toPresentationNodes(childrenNodes, getters, level + 1); } - return presentationNode; + return new NbTreeGridPresentationNode(dataGetter(node), children, expandedGetter(node), level); }); } @@ -36,14 +55,11 @@ export class NbTreeGridDataService { copy(nodes: NbTreeGridPresentationNode[]): NbTreeGridPresentationNode[] { return nodes.map((node: NbTreeGridPresentationNode) => { - const presentationNode = new NbTreeGridPresentationNode(node.node, node.level); - presentationNode.expanded = node.expanded; - + let children: NbTreeGridPresentationNode[]; if (node.hasChildren()) { - presentationNode.children = this.copy(node.children); + children = this.copy(node.children); } - - return presentationNode; + return new NbTreeGridPresentationNode(node.data, children, node.expanded, node.level); }); } } diff --git a/src/framework/theme/components/tree-grid/data-source/tree-grid-filter.service.ts b/src/framework/theme/components/tree-grid/data-source/tree-grid-filter.service.ts index 4320046578..bf78cf6662 100644 --- a/src/framework/theme/components/tree-grid/data-source/tree-grid-filter.service.ts +++ b/src/framework/theme/components/tree-grid/data-source/tree-grid-filter.service.ts @@ -30,7 +30,7 @@ export class NbTreeGridFilterService { if (filteredChildren && filteredChildren.length) { node.expanded = true; filtered.push(node); - } else if (this.filterPredicate(node.node.data, query)) { + } else if (this.filterPredicate(node.data, query)) { filtered.push(node); } diff --git a/src/framework/theme/components/tree-grid/data-source/tree-grid.model.ts b/src/framework/theme/components/tree-grid/data-source/tree-grid.model.ts index f4914a1847..35f3e2309d 100644 --- a/src/framework/theme/components/tree-grid/data-source/tree-grid.model.ts +++ b/src/framework/theme/components/tree-grid/data-source/tree-grid.model.ts @@ -4,52 +4,33 @@ * Licensed under the MIT License. See License.txt in the project root for license information. */ -/** - * Table's data interface - */ -export interface NbTreeGridNode { - /** - * Data object which will be available as a context of rows and cell templates - * @type T - */ - data: T, - /** - * Child rows - */ - children?: NbTreeGridNode[]; - /** - * Row expand state - */ - expanded?: boolean; -} +export const NB_DEFAULT_ROW_LEVEL: number = 0; + +export type NbDataGetter = (N) => T; +export type NbChildrenGetter = (N) => (T[] | undefined); +export type NbExpandedGetter = (N) => boolean; -export const DEFAULT_ROW_LEVEL: number = 0; +export interface NbGetters { + dataGetter?: NbDataGetter; + childrenGetter?: NbChildrenGetter; + expandedGetter?: NbExpandedGetter; +} /** * Implicit context of cells and rows */ export class NbTreeGridPresentationNode { - /** - * Row expand state - */ - get expanded(): boolean { - return this.node.expanded; - } - set expanded(value: boolean) { - this.node.expanded = value; - } - children: NbTreeGridPresentationNode[] = []; - - /** - * Data object associated with row - */ - get data(): T { - return this.node.data; - } - constructor( - readonly node: NbTreeGridNode, - public readonly level: number = DEFAULT_ROW_LEVEL, + /** + * Data object associated with row + */ + public readonly data: T, + public children: NbTreeGridPresentationNode[] | undefined, + /** + * Row expand state + */ + public expanded: boolean, + public readonly level: number, ) {} /** diff --git a/src/framework/theme/components/tree-grid/data-source/tree-grid.service.ts b/src/framework/theme/components/tree-grid/data-source/tree-grid.service.ts index 59efac4051..0c2f9b342f 100644 --- a/src/framework/theme/components/tree-grid/data-source/tree-grid.service.ts +++ b/src/framework/theme/components/tree-grid/data-source/tree-grid.service.ts @@ -46,7 +46,7 @@ export class NbTreeGridService { const toCheck: NbTreeGridPresentationNode[] = [...data]; for (const node of toCheck) { - if (node.node.data === row) { + if (node.data === row) { return node; } diff --git a/src/framework/theme/components/tree-grid/tree-grid-cell.component.ts b/src/framework/theme/components/tree-grid/tree-grid-cell.component.ts index 3c04bb0bef..8a91aca739 100644 --- a/src/framework/theme/components/tree-grid/tree-grid-cell.component.ts +++ b/src/framework/theme/components/tree-grid/tree-grid-cell.component.ts @@ -31,7 +31,7 @@ import { import { NB_TREE_GRID } from './tree-grid-injection-tokens'; import { NbTreeGridComponent } from './tree-grid.component'; import { NbTreeGridColumnDefDirective } from './tree-grid-column-def.directive'; -import { DEFAULT_ROW_LEVEL } from './data-source/tree-grid.model'; +import { NB_DEFAULT_ROW_LEVEL } from './data-source/tree-grid.model'; import { NbColumnsService } from './tree-grid-columns.service'; @Directive({ @@ -121,7 +121,7 @@ export class NbTreeGridCellDirective extends NbCellDirective implements OnInit, private getStartPadding(): string | SafeStyle | null { const rowLevel = this.tree.getCellLevel(this, this.columnDef.name); - if (rowLevel === DEFAULT_ROW_LEVEL) { + if (rowLevel === NB_DEFAULT_ROW_LEVEL) { return null; } diff --git a/src/framework/theme/components/tree-grid/tree-grid.component.spec.ts b/src/framework/theme/components/tree-grid/tree-grid.component.spec.ts index 176cfa85f7..97e0ace238 100644 --- a/src/framework/theme/components/tree-grid/tree-grid.component.spec.ts +++ b/src/framework/theme/components/tree-grid/tree-grid.component.spec.ts @@ -1,15 +1,34 @@ import { Component, QueryList, Type, ViewChild, ViewChildren } from '@angular/core'; -import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; +import { ComponentFixture, fakeAsync, inject, TestBed, tick } from '@angular/core/testing'; +import { EMPTY } from 'rxjs'; +import { take } from 'rxjs/operators'; +import createSpy = jasmine.createSpy; import { NbThemeModule, NbTreeGridComponent, NbTreeGridDataSource, NbTreeGridModule, - NbTreeGridNode, NbTreeGridRowComponent, NB_ROW_DOUBLE_CLICK_DELAY, + NbTreeGridDataSourceBuilder, + NbTreeGridPresentationNode, + NbGetters, } from '@nebular/theme'; +interface TreeNode { + data: T; + expanded?: boolean, + children?: TreeNode[]; +} + +interface CustomStructure { + a: string; + b: string; + c: string; + childNodes?: CustomStructure[]; + expanded?: boolean; +} + class BaseTreeGridTestComponent { columns: string[]; dataSource: NbTreeGridDataSource; @@ -50,7 +69,7 @@ export class TreeGridWithHeaderTestComponent extends BaseTreeGridTestComponent { function setupFixture( componentType: Type, columns: string[], - data?: NbTreeGridNode[], + data?: TreeNode[], ): ComponentFixture { TestBed.configureTestingModule({ @@ -69,24 +88,29 @@ function setupFixture( } const abcColumns: string[] = [ 'a', 'b', 'c' ]; -const twoRowsData: NbTreeGridNode[] = [ +const twoRowsData: TreeNode[] = [ { data: { a: 'a1', b: 'b1', c: 'c1' } }, { data: { a: 'a2', b: 'b2', c: 'c2' } }, ]; -const nestedRowData: NbTreeGridNode[] = [ +const nestedRowData: TreeNode[] = [ { data: { a: 'a1', b: 'b1', c: 'c1' }, children: [ { data: { a: 'a2', b: 'b2', c: 'c2' } } ], }, ]; -const nestedExpandedRowData: NbTreeGridNode[] = [ +const nestedExpandedRowData: TreeNode[] = [ { data: { a: 'a1', b: 'b1', c: 'c1' }, expanded: true, children: [ { data: { a: 'a2', b: 'b2', c: 'c2' } } ], }, ]; - +const customStructureData: CustomStructure[] = [ + { + a: 'a1', b: 'b1', c: 'c1', expanded: true, + childNodes: [{ a: 'a2', b: 'b2', c: 'c2' }], + }, +]; describe('NbTreeGridComponent', () => { @@ -177,4 +201,72 @@ describe('NbTreeGridComponent', () => { const rows = fixture.nativeElement.querySelectorAll('.nb-tree-grid-row'); expect(rows.length).toEqual(2); })); + + describe('NbTreeGridDataSourceBuilder custom node getters', () => { + const mockConnectionViewer = { viewChange: EMPTY }; + const getters: NbGetters = { + dataGetter: node => node, + childrenGetter: node => node.childNodes, + expandedGetter: node => !!node.expanded, + }; + let dataSourceBuilder: NbTreeGridDataSourceBuilder; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ NbThemeModule.forRoot(), NbTreeGridModule ], + }); + }); + beforeEach(inject([ NbTreeGridDataSourceBuilder ], builder => { + dataSourceBuilder = builder; + })); + + it('should use custom data accessor if provided', fakeAsync(() => { + const dataGetterSpy = createSpy('dataGetter', getters.dataGetter).and.callThrough(); + const spyGetters = { ...getters, dataGetter: dataGetterSpy }; + + const dataSource = dataSourceBuilder.create(customStructureData, spyGetters); + expect(dataGetterSpy).toHaveBeenCalledTimes(2); + + let presentationNodes: NbTreeGridPresentationNode[] = []; + dataSource.connect(mockConnectionViewer) + .pipe(take(1)) + .subscribe(nodes => presentationNodes = nodes as NbTreeGridPresentationNode[]); + tick(); + + expect(presentationNodes[0].data).toEqual(customStructureData[0]); + expect(presentationNodes[1].data).toEqual(customStructureData[0].childNodes[0]); + })); + + it('should use custom children accessor if provided', fakeAsync(() => { + const childrenGetterSpy = createSpy('childrenGetter', getters.childrenGetter).and.callThrough(); + const spyGetters = { ...getters, childrenGetter: childrenGetterSpy }; + + const dataSource = dataSourceBuilder.create(customStructureData, spyGetters); + expect(childrenGetterSpy).toHaveBeenCalledTimes(2); + + let presentationNodes: NbTreeGridPresentationNode[] = []; + dataSource.connect(mockConnectionViewer) + .pipe(take(1)) + .subscribe(nodes => presentationNodes = nodes as NbTreeGridPresentationNode[]); + tick(); + + expect(presentationNodes[0].data.childNodes[0]).toEqual(customStructureData[0].childNodes[0]); + })); + + it('should use custom expanded accessor if provided', fakeAsync(() => { + const expandedGetterSpy = createSpy('expandedGetter', getters.expandedGetter).and.callThrough(); + const spyGetters = { ...getters, expandedGetter: expandedGetterSpy }; + + const dataSource = dataSourceBuilder.create(customStructureData, spyGetters); + expect(expandedGetterSpy).toHaveBeenCalledTimes(2); + + let presentationNodes: NbTreeGridPresentationNode[] = []; + dataSource.connect(mockConnectionViewer) + .pipe(take(1)) + .subscribe(nodes => presentationNodes = nodes as NbTreeGridPresentationNode[]); + tick(); + + expect(presentationNodes[0].expanded).toEqual(true); + })); + }); }); diff --git a/src/framework/theme/components/tree-grid/tree-grid.component.ts b/src/framework/theme/components/tree-grid/tree-grid.component.ts index 9b2841de7e..a412a59cbf 100644 --- a/src/framework/theme/components/tree-grid/tree-grid.component.ts +++ b/src/framework/theme/components/tree-grid/tree-grid.component.ts @@ -11,7 +11,8 @@ import { ChangeDetectorRef, Component, ContentChildren, - ElementRef, HostBinding, + ElementRef, + HostBinding, Inject, Input, IterableDiffers, @@ -26,7 +27,7 @@ import { NbPlatform } from '../cdk/platform'; import { NbDirectionality } from '../cdk/bidi'; import { NB_TABLE_TEMPLATE, NbTable } from '../cdk/table'; import { NbTreeGridDataSource, NbTreeGridDataSourceBuilder } from './data-source/tree-grid-data-source'; -import { DEFAULT_ROW_LEVEL, NbTreeGridNode, NbTreeGridPresentationNode } from './data-source/tree-grid.model'; +import { NB_DEFAULT_ROW_LEVEL, NbTreeGridPresentationNode } from './data-source/tree-grid.model'; import { NbToggleOptions } from './data-source/tree-grid.service'; import { NB_TREE_GRID } from './tree-grid-injection-tokens'; import { NbTreeGridRowComponent } from './tree-grid-row.component'; @@ -45,13 +46,17 @@ import { NbColumnsService } from './tree-grid-columns.service'; * Supports filtering and sorting. * @stacked-example(Showcase, tree-grid/tree-grid-showcase.component) * - * Data provided to source should match [NbTreeGridNode](docs/components/treegrid/api#nbtreegridnode) interface. * As the most basic usage you need to define [nbTreeGridRowDef](docs/components/treegrid/api#nbtreegridrowdefdirective) * where you should pass columns to display in rows and * [nbTreeGridColumnDef](docs/components/treegrid/api#nbtreegridcolumndefdirective) - component containing cell * definitions for each column passed to row definition. * @stacked-example(Basic, tree-grid/tree-grid-basic.component) * + * `NbTreeGridComponent`'s source input and `NbTreeGridDataSourceBuilder.create` expecting data to be an array of + * objects with `data`, `children` and `expanded` properties. If your data doesn't match this interface, you can pass + * getter functions for each property as arguments to `NbTreeGridDataSourceBuilder.create` method. + * @stacked-example(Custom node structure, tree-grid/tree-grid-custom-node-structure.component) + * * To use sorting you can add `nbSort` directive to table and subscribe to `sort` method. When user click on header, * sort event will be emitted. Event object contain clicked column name and desired sort direction. * @stacked-example(Sortable, tree-grid/tree-grid-sortable.component) @@ -129,9 +134,9 @@ export class NbTreeGridComponent extends NbTable[] | NbTreeGridDataSource} + * @type {[] | NbTreeGridDataSource} */ - @Input('nbTreeGrid') set source(data: NbTreeGridNode[]) { + @Input('nbTreeGrid') set source(data: T[] | NbTreeGridDataSource) { if (!data) { return; } @@ -209,7 +214,7 @@ export class NbTreeGridComponent extends NbTable { + data: T; + children?: TreeNode[]; + expanded?: boolean; +} interface FSEntry { name: string; @@ -40,7 +45,7 @@ export class TreeGridBasicComponent { defaultColumns = [ 'size', 'kind', 'items' ]; allColumns = [ this.customColumn, ...this.defaultColumns ]; - data: NbTreeGridNode[] = [ + data: TreeNode[] = [ { data: { name: 'Projects', size: '1.8 MB', items: 5, kind: 'dir' }, children: [ diff --git a/src/playground/with-layout/tree-grid/tree-grid-custom-icons.component.ts b/src/playground/with-layout/tree-grid/tree-grid-custom-icons.component.ts index a5267d1dc1..492c0d8344 100644 --- a/src/playground/with-layout/tree-grid/tree-grid-custom-icons.component.ts +++ b/src/playground/with-layout/tree-grid/tree-grid-custom-icons.component.ts @@ -1,5 +1,11 @@ import { Component } from '@angular/core'; -import { NbTreeGridDataSource, NbTreeGridDataSourceBuilder, NbTreeGridNode } from '@nebular/theme'; +import { NbTreeGridDataSource, NbTreeGridDataSourceBuilder } from '@nebular/theme'; + +interface TreeNode { + data: T; + children?: TreeNode[]; + expanded?: boolean; +} interface FSEntry { name: string; @@ -64,7 +70,7 @@ export class TreeGridCustomIconsComponent { this.dataSource = dataSourceBuilder.create(this.data); } - private data: NbTreeGridNode[] = [ + private data: TreeNode[] = [ { data: { name: 'Projects', size: '1.8 MB', items: 5, kind: 'dir' }, children: [ diff --git a/src/playground/with-layout/tree-grid/tree-grid-custom-node-structure.component.ts b/src/playground/with-layout/tree-grid/tree-grid-custom-node-structure.component.ts new file mode 100644 index 0000000000..54beb6a9cb --- /dev/null +++ b/src/playground/with-layout/tree-grid/tree-grid-custom-node-structure.component.ts @@ -0,0 +1,99 @@ +import { Component } from '@angular/core'; +import { NbGetters, NbTreeGridDataSource, NbTreeGridDataSourceBuilder } from '@nebular/theme'; + +interface FSEntry { + name: string; + size: string; + kind: string; + items?: number; + childEntries?: FSEntry[]; + expanded?: boolean; +} + +@Component({ + template: ` + + + + + + + + + + + + + + + + +
{{customColumn}} + + {{row.data[customColumn]}} + {{column}}{{row.data[column] || '-'}}
+ +
+
+ `, + styleUrls: ['./tree-grid-shared.scss'], +}) +export class TreeGridCustomNodeStructureComponent { + customColumn = 'name'; + defaultColumns = [ 'size', 'kind', 'items' ]; + allColumns = [ this.customColumn, ...this.defaultColumns ]; + source: NbTreeGridDataSource; + + constructor(dataSourceBuilder: NbTreeGridDataSourceBuilder) { + const getters: NbGetters = { + dataGetter: (node: FSEntry) => node, + childrenGetter: (node: FSEntry) => node.childEntries || undefined, + expandedGetter: (node: FSEntry) => !!node.expanded, + }; + this.source = dataSourceBuilder.create(this.data, getters); + } + + private data: FSEntry[] = [ + { + name: 'Projects', size: '1.8 MB', items: 5, kind: 'dir', expanded: true, + childEntries: [ + { name: 'project-1.doc', kind: 'doc', size: '240 KB' }, + { name: 'project-2.doc', kind: 'doc', size: '290 KB' }, + { + name: 'project-3', kind: 'dir', size: '466 KB', items: 3, + childEntries: [ + { name: 'project-3A.doc', kind: 'doc', size: '200 KB' }, + { name: 'project-3B.doc', kind: 'doc', size: '266 KB' }, + { name: 'project-3C.doc', kind: 'doc', size: '0' }, + ], + }, + { name: 'project-4.docx', kind: 'docx', size: '900 KB' }, + ], + }, + { + name: 'Reports', kind: 'dir', size: '400 KB', items: 2, + childEntries: [ + { + name: 'Report 1', kind: 'dir', size: '100 KB', items: 1, + childEntries: [ + { name: 'report-1.doc', kind: 'doc', size: '100 KB' }, + ], + }, + { + name: 'Report 2', kind: 'dir', size: '300 KB', items: 2, + childEntries: [ + { name: 'report-2.doc', kind: 'doc', size: '290 KB' }, + { name: 'report-2-note.txt', kind: 'txt', size: '10 KB' }, + ], + }, + ], + }, + { + name: 'Other', kind: 'dir', size: '109 MB', items: 2, + childEntries: [ + { name: 'backup.bkp', kind: 'bkp', size: '107 MB' }, + { name: 'secret-note.txt', kind: 'txt', size: '2 MB' }, + ], + }, + ]; +} diff --git a/src/playground/with-layout/tree-grid/tree-grid-disable-click-toggle.component.ts b/src/playground/with-layout/tree-grid/tree-grid-disable-click-toggle.component.ts index 2090e54369..e1c061dfbe 100644 --- a/src/playground/with-layout/tree-grid/tree-grid-disable-click-toggle.component.ts +++ b/src/playground/with-layout/tree-grid/tree-grid-disable-click-toggle.component.ts @@ -1,5 +1,10 @@ import { Component } from '@angular/core'; -import { NbTreeGridNode } from '@nebular/theme'; + +interface TreeNode { + data: T; + children?: TreeNode[]; + expanded?: boolean; +} interface FSEntry { name: string; @@ -40,7 +45,7 @@ export class TreeGridDisableClickToggleComponent { defaultColumns = [ 'size', 'kind', 'items' ]; allColumns = [ this.customColumn, ...this.defaultColumns ]; - data: NbTreeGridNode[] = [ + data: TreeNode[] = [ { data: { name: 'Projects', size: '1.8 MB', items: 5, kind: 'dir' }, children: [ diff --git a/src/playground/with-layout/tree-grid/tree-grid-filterable.component.ts b/src/playground/with-layout/tree-grid/tree-grid-filterable.component.ts index 5b36740eb5..4b5f958221 100644 --- a/src/playground/with-layout/tree-grid/tree-grid-filterable.component.ts +++ b/src/playground/with-layout/tree-grid/tree-grid-filterable.component.ts @@ -1,5 +1,11 @@ import { Component } from '@angular/core'; -import { NbTreeGridDataSource, NbTreeGridDataSourceBuilder, NbTreeGridNode } from '@nebular/theme'; +import { NbTreeGridDataSource, NbTreeGridDataSourceBuilder } from '@nebular/theme'; + +interface TreeNode { + data: T; + children?: TreeNode[]; + expanded?: boolean; +} interface FSEntry { name: string; @@ -59,7 +65,7 @@ export class TreeGridFilterableComponent { this.dataSource.filter(event.target.value); } - private data: NbTreeGridNode[] = [ + private data: TreeNode[] = [ { data: { name: 'Projects', size: '1.8 MB', items: 5, kind: 'dir' }, children: [ diff --git a/src/playground/with-layout/tree-grid/tree-grid-responsive.component.ts b/src/playground/with-layout/tree-grid/tree-grid-responsive.component.ts index 485ab17540..5968d32e73 100644 --- a/src/playground/with-layout/tree-grid/tree-grid-responsive.component.ts +++ b/src/playground/with-layout/tree-grid/tree-grid-responsive.component.ts @@ -1,5 +1,10 @@ import { Component } from '@angular/core'; -import { NbTreeGridNode } from '@nebular/theme'; + +interface TreeNode { + data: T; + children?: TreeNode[]; + expanded?: boolean; +} interface FSEntry { name: string; @@ -50,7 +55,7 @@ interface FSEntry { export class TreeGridResponsiveComponent { allColumns = [ 'name', 'size', 'kind', 'items' ]; - data: NbTreeGridNode[] = [ + data: TreeNode[] = [ { data: { name: 'Projects', size: '1.8 MB', items: 5, kind: 'dir' }, children: [ diff --git a/src/playground/with-layout/tree-grid/tree-grid-routing.module.ts b/src/playground/with-layout/tree-grid/tree-grid-routing.module.ts index 36bdac73cd..13745c2163 100644 --- a/src/playground/with-layout/tree-grid/tree-grid-routing.module.ts +++ b/src/playground/with-layout/tree-grid/tree-grid-routing.module.ts @@ -13,6 +13,7 @@ import { TreeGridBasicComponent } from './tree-grid-basic.component'; import { TreeGridResponsiveComponent } from './tree-grid-responsive.component'; import { TreeGridCustomIconsComponent } from './tree-grid-custom-icons.component'; import { TreeGridDisableClickToggleComponent } from './tree-grid-disable-click-toggle.component'; +import { TreeGridCustomNodeStructureComponent } from './tree-grid-custom-node-structure.component'; const routes: Route[] = [ { @@ -43,6 +44,10 @@ const routes: Route[] = [ path: 'tree-grid-disable-click-toggle.component', component: TreeGridDisableClickToggleComponent, }, + { + path: 'tree-grid-custom-node-structure.component', + component: TreeGridCustomNodeStructureComponent, + }, ]; @NgModule({ diff --git a/src/playground/with-layout/tree-grid/tree-grid-showcase.component.ts b/src/playground/with-layout/tree-grid/tree-grid-showcase.component.ts index 16e04db5bd..adbd220c8c 100644 --- a/src/playground/with-layout/tree-grid/tree-grid-showcase.component.ts +++ b/src/playground/with-layout/tree-grid/tree-grid-showcase.component.ts @@ -5,13 +5,13 @@ */ import { Component } from '@angular/core'; -import { - NbSortDirection, - NbSortRequest, - NbTreeGridDataSource, - NbTreeGridDataSourceBuilder, - NbTreeGridNode, -} from '@nebular/theme'; +import { NbSortDirection, NbSortRequest, NbTreeGridDataSource, NbTreeGridDataSourceBuilder } from '@nebular/theme'; + +interface TreeNode { + data: T; + children?: TreeNode[]; + expanded?: boolean; +} interface FSEntry { name: string; @@ -51,7 +51,7 @@ export class TreeGridShowcaseComponent { return NbSortDirection.NONE; } - private data: NbTreeGridNode[] = [ + private data: TreeNode[] = [ { data: { name: 'Projects', size: '1.8 MB', items: 5, kind: 'dir' }, children: [ diff --git a/src/playground/with-layout/tree-grid/tree-grid-sortable.component.ts b/src/playground/with-layout/tree-grid/tree-grid-sortable.component.ts index d52dcf75bc..b5a74d8a4d 100644 --- a/src/playground/with-layout/tree-grid/tree-grid-sortable.component.ts +++ b/src/playground/with-layout/tree-grid/tree-grid-sortable.component.ts @@ -1,11 +1,11 @@ import { Component } from '@angular/core'; -import { - NbSortDirection, - NbSortRequest, - NbTreeGridDataSource, - NbTreeGridDataSourceBuilder, - NbTreeGridNode, -} from '@nebular/theme'; +import { NbSortDirection, NbSortRequest, NbTreeGridDataSource, NbTreeGridDataSourceBuilder } from '@nebular/theme'; + +interface TreeNode { + data: T; + children?: TreeNode[]; + expanded?: boolean; +} interface FSEntry { name: string; @@ -77,7 +77,7 @@ export class TreeGridSortableComponent { return NbSortDirection.NONE; } - private data: NbTreeGridNode[] = [ + private data: TreeNode[] = [ { data: { name: 'Projects', size: '1.8 MB', items: 5, kind: 'dir' }, children: [ diff --git a/src/playground/with-layout/tree-grid/tree-grid.module.ts b/src/playground/with-layout/tree-grid/tree-grid.module.ts index f7839cf52a..bb1b28d0be 100644 --- a/src/playground/with-layout/tree-grid/tree-grid.module.ts +++ b/src/playground/with-layout/tree-grid/tree-grid.module.ts @@ -17,6 +17,7 @@ import { TreeGridResponsiveComponent } from './tree-grid-responsive.component'; import { FsIconComponent } from './components/fs-icon.component'; import { TreeGridCustomIconsComponent } from './tree-grid-custom-icons.component'; import { TreeGridDisableClickToggleComponent } from './tree-grid-disable-click-toggle.component'; +import { TreeGridCustomNodeStructureComponent } from './tree-grid-custom-node-structure.component'; @NgModule({ imports: [ CommonModule, NbTreeGridModule, TreeGridRoutingModule, NbCardModule, NbInputModule ], @@ -29,6 +30,7 @@ import { TreeGridDisableClickToggleComponent } from './tree-grid-disable-click-t TreeGridResponsiveComponent, TreeGridCustomIconsComponent, TreeGridDisableClickToggleComponent, + TreeGridCustomNodeStructureComponent, ], }) export class TreeGridModule {}