Skip to content

Commit c6e06c1

Browse files
committed
feat(tree): make data source accept array or observable
1 parent bce166b commit c6e06c1

File tree

6 files changed

+306
-19
lines changed

6 files changed

+306
-19
lines changed

src/cdk/tree/tree-errors.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9+
/**
10+
* Returns an error to be thrown when there is no usable data.
11+
* @docs-private
12+
*/
13+
export function getTreeNoValidDataSourceError() {
14+
return Error(`A valid data source must be provided.`);
15+
}
16+
917
/**
1018
* Returns an error to be thrown when there are multiple nodes that are missing a when function.
1119
* @docs-private

src/cdk/tree/tree.spec.ts

Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,84 @@ describe('CdkTree', () => {
218218
[`[topping_3] - [cheese_3] + [base_3]`]);
219219
});
220220
});
221+
222+
describe('with array data source', () => {
223+
let fixture: ComponentFixture<ArrayDataSourceCdkTreeApp>;
224+
let component: ArrayDataSourceCdkTreeApp;
225+
226+
beforeEach(() => {
227+
configureCdkTreeTestingModule([ArrayDataSourceCdkTreeApp]);
228+
fixture = TestBed.createComponent(ArrayDataSourceCdkTreeApp);
229+
230+
component = fixture.componentInstance;
231+
dataSource = component.dataSource as FakeDataSource;
232+
tree = component.tree;
233+
treeElement = fixture.nativeElement.querySelector('cdk-tree');
234+
235+
fixture.detectChanges();
236+
});
237+
238+
it('with the right data', () => {
239+
expect(dataSource.data.length).toBe(3);
240+
241+
let data = dataSource.data;
242+
expectFlatTreeToMatch(treeElement, 28,
243+
[`[topping_1] - [cheese_1] + [base_1]`],
244+
[`[topping_2] - [cheese_2] + [base_2]`],
245+
[`[topping_3] - [cheese_3] + [base_3]`]);
246+
247+
dataSource.addChild(data[1]);
248+
fixture.detectChanges();
249+
250+
treeElement = fixture.nativeElement.querySelector('cdk-tree');
251+
data = dataSource.data;
252+
expect(data.length).toBe(4);
253+
expectFlatTreeToMatch(treeElement, 28,
254+
[`[topping_1] - [cheese_1] + [base_1]`],
255+
[`[topping_2] - [cheese_2] + [base_2]`],
256+
[_, `[topping_4] - [cheese_4] + [base_4]`],
257+
[`[topping_3] - [cheese_3] + [base_3]`]);
258+
});
259+
});
260+
261+
describe('with observable data source', () => {
262+
let fixture: ComponentFixture<ObservableDataSourceCdkTreeApp>;
263+
let component: ObservableDataSourceCdkTreeApp;
264+
265+
beforeEach(() => {
266+
configureCdkTreeTestingModule([ObservableDataSourceCdkTreeApp]);
267+
fixture = TestBed.createComponent(ObservableDataSourceCdkTreeApp);
268+
269+
component = fixture.componentInstance;
270+
dataSource = component.dataSource as FakeDataSource;
271+
tree = component.tree;
272+
treeElement = fixture.nativeElement.querySelector('cdk-tree');
273+
274+
fixture.detectChanges();
275+
});
276+
277+
it('with the right data', () => {
278+
expect(dataSource.data.length).toBe(3);
279+
280+
let data = dataSource.data;
281+
expectFlatTreeToMatch(treeElement, 28,
282+
[`[topping_1] - [cheese_1] + [base_1]`],
283+
[`[topping_2] - [cheese_2] + [base_2]`],
284+
[`[topping_3] - [cheese_3] + [base_3]`]);
285+
286+
dataSource.addChild(data[1]);
287+
fixture.detectChanges();
288+
289+
treeElement = fixture.nativeElement.querySelector('cdk-tree');
290+
data = dataSource.data;
291+
expect(data.length).toBe(4);
292+
expectFlatTreeToMatch(treeElement, 28,
293+
[`[topping_1] - [cheese_1] + [base_1]`],
294+
[`[topping_2] - [cheese_2] + [base_2]`],
295+
[_, `[topping_4] - [cheese_4] + [base_4]`],
296+
[`[topping_3] - [cheese_3] + [base_3]`]);
297+
});
298+
});
221299
});
222300

223301
describe('nested tree', () => {
@@ -435,6 +513,80 @@ describe('CdkTree', () => {
435513
[`topping_3 - cheese_3 + base_3`]);
436514
});
437515
});
516+
517+
describe('with array data source', () => {
518+
let fixture: ComponentFixture<ArrayDataSourceNestedCdkTreeApp>;
519+
let component: ArrayDataSourceNestedCdkTreeApp;
520+
521+
beforeEach(() => {
522+
configureCdkTreeTestingModule([ArrayDataSourceNestedCdkTreeApp]);
523+
fixture = TestBed.createComponent(ArrayDataSourceNestedCdkTreeApp);
524+
525+
component = fixture.componentInstance;
526+
dataSource = component.dataSource as FakeDataSource;
527+
tree = component.tree;
528+
treeElement = fixture.nativeElement.querySelector('cdk-tree');
529+
530+
fixture.detectChanges();
531+
});
532+
533+
it('with the right data', () => {
534+
expect(dataSource.data.length).toBe(3);
535+
536+
let data = dataSource.data;
537+
expectNestedTreeToMatch(treeElement,
538+
[`[topping_1] - [cheese_1] + [base_1]`],
539+
[`[topping_2] - [cheese_2] + [base_2]`],
540+
[`[topping_3] - [cheese_3] + [base_3]`]);
541+
542+
dataSource.addChild(data[1], false);
543+
fixture.detectChanges();
544+
545+
treeElement = fixture.nativeElement.querySelector('cdk-tree');
546+
expectNestedTreeToMatch(treeElement,
547+
[`[topping_1] - [cheese_1] + [base_1]`],
548+
[`[topping_2] - [cheese_2] + [base_2]`],
549+
[_, `[topping_4] - [cheese_4] + [base_4]`],
550+
[`[topping_3] - [cheese_3] + [base_3]`]);
551+
});
552+
});
553+
554+
describe('with observable data source', () => {
555+
let fixture: ComponentFixture<ObservableDataSourceNestedCdkTreeApp>;
556+
let component: ObservableDataSourceNestedCdkTreeApp;
557+
558+
beforeEach(() => {
559+
configureCdkTreeTestingModule([ObservableDataSourceNestedCdkTreeApp]);
560+
fixture = TestBed.createComponent(ObservableDataSourceNestedCdkTreeApp);
561+
562+
component = fixture.componentInstance;
563+
dataSource = component.dataSource as FakeDataSource;
564+
tree = component.tree;
565+
treeElement = fixture.nativeElement.querySelector('cdk-tree');
566+
567+
fixture.detectChanges();
568+
});
569+
570+
it('with the right data', () => {
571+
expect(dataSource.data.length).toBe(3);
572+
573+
let data = dataSource.data;
574+
expectNestedTreeToMatch(treeElement,
575+
[`[topping_1] - [cheese_1] + [base_1]`],
576+
[`[topping_2] - [cheese_2] + [base_2]`],
577+
[`[topping_3] - [cheese_3] + [base_3]`]);
578+
579+
dataSource.addChild(data[1], false);
580+
fixture.detectChanges();
581+
582+
treeElement = fixture.nativeElement.querySelector('cdk-tree');
583+
expectNestedTreeToMatch(treeElement,
584+
[`[topping_1] - [cheese_1] + [base_1]`],
585+
[`[topping_2] - [cheese_2] + [base_2]`],
586+
[_, `[topping_4] - [cheese_4] + [base_4]`],
587+
[`[topping_3] - [cheese_3] + [base_3]`]);
588+
});
589+
});
438590
});
439591
});
440592

@@ -740,4 +892,105 @@ class WhenNodeCdkTreeApp {
740892
@ViewChild(CdkTree) tree: CdkTree<TestData>;
741893
}
742894

895+
@Component({
896+
template: `
897+
<cdk-tree [dataSource]="dataArray" [treeControl]="treeControl">
898+
<cdk-tree-node *cdkTreeNodeDef="let node"
899+
cdkTreeNodePadding [cdkTreeNodePaddingIndent]="28"
900+
cdkTreeNodeToggle>
901+
[{{node.pizzaTopping}}] - [{{node.pizzaCheese}}] + [{{node.pizzaBase}}]
902+
</cdk-tree-node>
903+
</cdk-tree>
904+
`
905+
})
906+
class ArrayDataSourceCdkTreeApp {
907+
getLevel = (node: TestData) => node.level;
908+
isExpandable = (node: TestData) => node.children.length > 0;
909+
910+
treeControl: TreeControl<TestData> = new FlatTreeControl(this.getLevel, this.isExpandable);
911+
912+
dataSource: FakeDataSource = new FakeDataSource(this.treeControl);
913+
914+
get dataArray() {
915+
return this.dataSource.data;
916+
}
917+
918+
@ViewChild(CdkTree) tree: CdkTree<TestData>;
919+
}
920+
921+
@Component({
922+
template: `
923+
<cdk-tree [dataSource]="dataObservable" [treeControl]="treeControl">
924+
<cdk-tree-node *cdkTreeNodeDef="let node"
925+
cdkTreeNodePadding [cdkTreeNodePaddingIndent]="28"
926+
cdkTreeNodeToggle>
927+
[{{node.pizzaTopping}}] - [{{node.pizzaCheese}}] + [{{node.pizzaBase}}]
928+
</cdk-tree-node>
929+
</cdk-tree>
930+
`
931+
})
932+
class ObservableDataSourceCdkTreeApp {
933+
getLevel = (node: TestData) => node.level;
934+
isExpandable = (node: TestData) => node.children.length > 0;
935+
936+
treeControl: TreeControl<TestData> = new FlatTreeControl(this.getLevel, this.isExpandable);
937+
938+
dataSource: FakeDataSource = new FakeDataSource(this.treeControl);
939+
940+
get dataObservable() {
941+
return this.dataSource._dataChange;
942+
}
943+
944+
@ViewChild(CdkTree) tree: CdkTree<TestData>;
945+
}
946+
947+
@Component({
948+
template: `
949+
<cdk-tree [dataSource]="dataArray" [treeControl]="treeControl">
950+
<cdk-nested-tree-node *cdkTreeNodeDef="let node">
951+
[{{node.pizzaTopping}}] - [{{node.pizzaCheese}}] + [{{node.pizzaBase}}]
952+
<ng-template cdkTreeNodeOutlet></ng-template>
953+
</cdk-nested-tree-node>
954+
</cdk-tree>
955+
`
956+
})
957+
class ArrayDataSourceNestedCdkTreeApp {
958+
959+
getChildren = (node: TestData) => node.observableChildren;
960+
961+
treeControl: TreeControl<TestData> = new NestedTreeControl(this.getChildren);
962+
963+
dataSource: FakeDataSource = new FakeDataSource(this.treeControl);
964+
965+
get dataArray() {
966+
return this.dataSource.data;
967+
}
968+
969+
@ViewChild(CdkTree) tree: CdkTree<TestData>;
970+
}
971+
972+
@Component({
973+
template: `
974+
<cdk-tree [dataSource]="dataObservable" [treeControl]="treeControl">
975+
<cdk-nested-tree-node *cdkTreeNodeDef="let node">
976+
[{{node.pizzaTopping}}] - [{{node.pizzaCheese}}] + [{{node.pizzaBase}}]
977+
<ng-template cdkTreeNodeOutlet></ng-template>
978+
</cdk-nested-tree-node>
979+
</cdk-tree>
980+
`
981+
})
982+
class ObservableDataSourceNestedCdkTreeApp {
983+
984+
getChildren = (node: TestData) => node.observableChildren;
985+
986+
treeControl: TreeControl<TestData> = new NestedTreeControl(this.getChildren);
987+
988+
dataSource: FakeDataSource = new FakeDataSource(this.treeControl);
989+
990+
get dataObservable() {
991+
return this.dataSource._dataChange;
992+
}
993+
994+
@ViewChild(CdkTree) tree: CdkTree<TestData>;
995+
}
743996

0 commit comments

Comments
 (0)